home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1990-07-19 | 2.4 MB | 79,625 lines | [ TEXT/MPS ]
Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
æKY CopyrightNotice æC Copyright Apple Computer, Inc. 1985-1990, All rights reserved. 411 - PInterfaces Help - QR 1 Release. Friday, July 6, 1990 3:27:56 PM æKY Help PInterfacesHelp æKL AboutPInterfacesHelp.p ADSP.p Aliases.p AppleEvents.p AppleTalk.p Balloons.p Controls.p CursorCtl.p DatabaseAccess.p DDev.p Desk.p DeskBus.p Devices.p Dialogs.p DisAsmLookup.p DiskInit.p Disks.p Editions.p EPPC.p ErrMgr.p Errors.p Events.p Files.p FixMath.p Folders.p Fonts.p GestaltEqu.p Globals.p Graf3D.p HyperXCmd.p Lists.p Memory.p Menus.p MIDI.p Notification.p OSEvents.p OSUtils.p Packages.p Palettes.p Perf.p Picker.p Power.p PPCToolBox.p PrintTraps.p Processes.p QDOffscreen.p Quickdraw.p Resources.p Retrace.p ROMDefs.p SANE.p Scrap.p Script.p SCSI.p SCSIIntf.p SegLoad.p Serial.p ShutDown.p Signal.p Slots.p Sound.p StandardFile.p Start.p Strings.p SysEqu.p TextEdit.p Timer.p ToolUtils.p Types.p Video.p Windows.p æKY AboutPInterfacesHelp.p æC Version 1.0 Beta: This version contains the InsideMacintosh Volume VI information. æKY ADSP.p æKL attnBufSize dspAttention dspCLDeny dspCLInit dspCLListen dspClose dspCLRemove dspInit dspNewCID dspOpen dspOptions DSPParamBlock DSPPBPtr dspRead dspRemove dspReset dspStatus dspWrite eAttention eClosed eFwdReset errAborted errAttention errFwdReset errOpening errRefNum errState eTearDown ocAccept ocEstablish ocPassive ocRequest sClosed sClosing sListening sOpen sOpening sPassive TPCCB TRCCB æKY errRefNum æFp ADSP.p æT CONST æD { constants result codes } errRefNum = -1280; { bad connection refNum } æC æKY errAborted æFp ADSP.p æT CONST æD errAborted = -1279; { control call was aborted } æC æKY errState æFp ADSP.p æT CONST æD errState = -1278; { bad connection state for this operation } æC æKY errOpening æFp ADSP.p æT CONST æD errOpening = -1277; { open connection request was denied } æC æKY errAttention æFp ADSP.p æT CONST æD errAttention = -1276; { attention message too long } æC æKY errFwdReset æFp ADSP.p æT CONST æD errFwdReset = -1275; { read terminated by forward reset } æC æKY dspInit æFp ADSP.p æT CONST æD { control codes } dspInit = 255; { create a new connection end } æC æKY dspRemove æFp ADSP.p æT CONST æD dspRemove = 254; { remove a connection end } æC æKY dspOpen æFp ADSP.p æT CONST æD dspOpen = 253; { open a connection } æC æKY dspClose æFp ADSP.p æT CONST æD dspClose = 252; { close a connection } æC æKY dspCLInit æFp ADSP.p æT CONST æD dspCLInit = 251; { create a connection listener } æC æKY dspCLRemove æFp ADSP.p æT CONST æD dspCLRemove = 250; { remove a connection listener } æC æKY dspCLListen æFp ADSP.p æT CONST æD dspCLListen = 249; { post a listener request } æC æKY dspCLDeny æFp ADSP.p æT CONST æD dspCLDeny = 248; { deny an open connection request } æC æKY dspStatus æFp ADSP.p æT CONST æD dspStatus = 247; { get status of connection end } æC æKY dspRead æFp ADSP.p æT CONST æD dspRead = 246; { read data from the connection } æC æKY dspWrite æFp ADSP.p æT CONST æD dspWrite = 245; { write data on the connection } æC æKY dspAttention æFp ADSP.p æT CONST æD dspAttention = 244; { send an attention message } æC æKY dspOptions æFp ADSP.p æT CONST æD dspOptions = 243; { set connection end options } æC æKY dspReset æFp ADSP.p æT CONST æD dspReset = 242; { forward reset the connection } æC æKY dspNewCID æFp ADSP.p æT CONST æD dspNewCID = 241; { generate a cid for a connection end } æC æKY ocRequest æFp ADSP.p æT CONST æD { connection opening modes } ocRequest = 1; { request a connection with remote } æC æKY ocPassive æFp ADSP.p æT CONST æD ocPassive = 2; { wait for a connection request from remote } æC æKY ocAccept æFp ADSP.p æT CONST æD ocAccept = 3; { accept request as delivered by listener } æC æKY ocEstablish æFp ADSP.p æT CONST æD ocEstablish = 4; { consider connection to be open } æC æKY sListening æFp ADSP.p æT CONST æD { connection end states } sListening = 1; { for connection listeners } æC æKY sPassive æFp ADSP.p æT CONST æD sPassive = 2; { waiting for a connection request from remote } æC æKY sOpening æFp ADSP.p æT CONST æD sOpening = 3; { requesting a connection with remote } æC æKY sOpen æFp ADSP.p æT CONST æD sOpen = 4; { connection is open } æC æKY sClosing æFp ADSP.p æT CONST æD sClosing = 5; { connection is being torn down } æC æKY sClosed æFp ADSP.p æT CONST æD sClosed = 6; { connection end state is closed } æC æKY eClosed æFp ADSP.p æT CONST æD { client event flags } eClosed = $80; { received connection closed advice } æC æKY eTearDown æFp ADSP.p æT CONST æD eTearDown = $40; { connection closed due to broken connection } æC æKY eAttention æFp ADSP.p æT CONST æD eAttention = $20; { received attention message } æC æKY eFwdReset æFp ADSP.p æT CONST æD eFwdReset = $10; { received forward reset advice } æC æKY attnBufSize æFp ADSP.p æT CONST æD { miscellaneous constants } attnBufSize = 570; { size of client attention buffer } æC æKY TRCCB TPCCB æFp ADSP.p æT RECORD æD TPCCB = ^TRCCB; TRCCB = PACKED RECORD ccbLink: TPCCB; { link to next ccb } refNum: INTEGER; { user reference number } state: INTEGER; { state of the connection end } userFlags: Byte; { flags for unsolicited connection events } localSocket: Byte; { socket number of this connection end } remoteAddress: AddrBlock; { internet address of remote end } attnCode: INTEGER; { attention code received } attnSize: INTEGER; { size of received attention data } attnPtr: Ptr; { ptr to received attention data } reserved: PACKED ARRAY [1..220] OF Byte; { adsp internal use } END; æC æKY DSPParamBlock DSPPBPtr æFp ADSP.p æT RECORD æD DSPPBPtr = ^DSPParamBlock; DSPParamBlock = RECORD qLink: QElemPtr; qType: INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion: ProcPtr; ioResult: OSErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; ioCRefNum: INTEGER; { adsp driver refnum } csCode: INTEGER; { adsp driver control code } qStatus: LONGINT; { adsp internal use } ccbRefNum: INTEGER; { connection end reNum} CASE Integer OF dspInit,dspCLInit: (ccbPtr: TPCCB; {pointer to connection control block} userRoutine: ProcPtr; {client routine to call on event} sendQSize: INTEGER; {size of send queue (0..64K bytes)} sendQueue: Ptr; {client passed send queue buffer} recvQSize: INTEGER; {size of receive queue (0..64K bytes)} recvQueue: Ptr ; {client passed receive queue buffer} attnPtr: Ptr; {client passed receive attention buffer} localSocket: Byte; {local socket number} filler1: Byte; {filler for proper byte alignment}} ); dspOpen,dspCLListen,dspCLDeny: (localCID: INTEGER; {local connection id} remoteCID: INTEGER; {remote connection id} remoteAddress: AddrBlock; {address of remote end} filterAddress: AddrBlock; {address filter} sendSeq: LONGINT; {local send sequence number} sendWindow: INTEGER; {send window size} recvSeq: LONGINT; {receive sequence number} attnSendSeq: LONGINT; {attention send sequence number} attnRecvSeq: LONGINT; {attention receive sequence number} ocMode: Byte; {open connection mode} ocInterval: Byte; {open connection request retry interval} ocMaximum: Byte; {open connection request retry maximum} filler2: Byte; {filler for proper byte alignment} ); dspClose,dspRemove: (abort: Byte; {abort connection immediately if non-zero} filler3: Byte; {filler for proper byte alignment} ); dspStatus: (statusCCB: TPCCB; {pointer to ccb} sendQPending: INTEGER; {pending bytes in send queue} sendQFree: INTEGER; {available buffer space in send queue} recvQPending: INTEGER; {pending bytes in receive queue} recvQFree: INTEGER; {available buffer space in receive queue} ); dspRead,dspWrite: (reqCount: INTEGER; {requested number of bytes} actCount: INTEGER; {actual number of bytes} dataPtr: Ptr; {pointer to data buffer} eom: Byte; {indicates logical end of message} flush: Byte; {send data now} ); dspAttention: (attnCode: INTEGER; {client attention code} attnSize: INTEGER; {size of attention data} attnData: Ptr; {pointer to attention data} attnInterval: Byte; {retransmit timer in 10-tick intervals} filler4: Byte; {filler for proper byte alignment} ); dspOptions: (sendBlocking: INTEGER; {quantum for data packets} sendTimer: Byte; {send timer in 10-tick intervals} rtmtTimer: Byte; {retransmit timer in 10-tick intervals} badSeqMax: Byte; {threshold for sending retransmit advice} useCheckSum: Byte; {use ddp packet checksum} ); dspNewCID: (newCID: INTEGER; {new connection id returned} ); END; æC æKY Aliases.p æKL CanonifyFile GetAliasInfo MatchAlias NewAlias NewAliasMinimal NewAliasMinimalFromFullpath ResolveAlias SelectAlias UpdateAlias AliasHandle AliasInfoType AliasPtr AliasRecord asiAliasName asiParentName asiServerName asiVolumeName asiZoneName CanonicalFileSpec CanonicalFileSpecList CanonicalFileSpecListPtr kARMmountVol kARMmultVols kARMnoUI kARMsearch kARMsearchMore kARMsearchRelFirst rAliasType æKY rAliasType æFp Aliases.p æT CONST æD { Constants } rAliasType = 'alis'; { Aliases are stored as resources of this type } æC æKY kARMmountVol æFp Aliases.p æT CONST æD { define alias resolution action rules mask } kARMmountVol = $00000001; { mount the volume automatically } æC æKY kARMnoUI æFp Aliases.p æT CONST æD kARMnoUI = $00000002; { no user interface allowed during resolution } æC æKY kARMmultVols æFp Aliases.p æT CONST æD kARMmultVols = $00000008; { search on multiple volumes } æC æKY kARMsearch æFp Aliases.p æT CONST æD kARMsearch = $00000100; { search quickly } æC æKY kARMsearchMore æFp Aliases.p æT CONST æD kARMsearchMore = $00000200; { search further } æC æKY kARMsearchRelFirst æFp Aliases.p æT CONST æD kARMsearchRelFirst = $00000400; { search target on a relative path first } æC æKY asiZoneName æFp Aliases.p æT CONST æD { define alias record information types } asiZoneName = -3; { get zone name } æC æKY asiServerName æFp Aliases.p æT CONST æD asiServerName = -2; { get server name } æC æKY asiVolumeName æFp Aliases.p æT CONST æD asiVolumeName = -1; { get volume name } æC æKY asiAliasName æFp Aliases.p æT CONST æD asiAliasName = 0; { get aliased file/folder/volume name } æC æKY asiParentName æFp Aliases.p æT CONST æD asiParentName = 1; { get parent folder name } æC æKY CanonicalFileSpec CanonicalFileSpecList æFp Aliases.p æT RECORD æD CanonicalFileSpecList = ^CanonicalFileSpec; CanonicalFileSpec = RECORD vRefNum: INTEGER; { volume reference number } dirID: LONGINT; { directory ID } fileName: Str63; { file name } END; æC æKY AliasRecord AliasPtr AliasHandle æFp Aliases.p æT RECORD æD AliasPtr = ^AliasRecord; AliasHandle = ^AliasPtr; AliasRecord = RECORD userType: OSType; { appl stored type like creator type } aliasSize: INTEGER; { alias record size in bytes, for appl usage} END; { define the alias record that will be the blackbox for the caller } æC æKY AliasInfoType æFp Aliases.p æT RECORD æD AliasInfoType = INTEGER; { alias record information type } æC æKY CanonifyFile æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION CanonifyFile(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255; VAR canonicalFile: CanonicalFileSpec): OSErr; INLINE $7001,$A823; { Public Interfaces High Level Routines given a volume reference number (or a working directory reference number), directory ID and a file name, return the canonical form of the specified file } æDT myVariable := CanonifyFile(vRefNum,dirID,fileName,canonicalFile); æC æKY NewAlias æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION NewAlias(fromFile: CanonicalFileSpecPtr;target: CanonicalFileSpec; VAR alias: AliasHandle): OSErr; INLINE $7002,$A823; { create a new alias between fromFile-target and return alias record handle } æDT myVariable := NewAlias(fromFile,target,alias); æC You use the NewAlias function to create an alias record. FUNCTION NewAlias (fromFile,target: FSSpecPtr; VAR alias: AliasHandle) : OSErr; NewAlias creates an alias record that describes the object specified in the target parameter. It fills in the record and puts a record handle in the alias parameter. The fromFile parameter represents the starting point for a relative search. This parameter can be either NIL or a pointer to a valid FSSpec record. If fromFile is NIL, the alias record does not include relative path information. Specify a value for fromFile only if you want NewAlias to record relative path information. The target parameter points to a FSSpec record for the file, folder, or volume to be described by the alias record. The alias parameter is the handle for the newly created alias record. If the function fails to create an alias record, it sets alias to NIL. Result codes paramErr -50 The target parameter is NIL æKY NewAliasMinimal æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION NewAliasMinimal(target: CanonicalFileSpec;VAR alias: AliasHandle): OSErr; INLINE $7008,$A823; { create a minimal new alias for a target and return alias record handle } æDT myVariable := NewAliasMinimal(target,alias); æC æKY NewAliasMinimalFromFullpath æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION NewAliasMinimalFromFullpath(fullpathLength: INTEGER;fullpath: Ptr; zoneName: Str31;serverName: Str31;VAR alias: AliasHandle): OSErr; INLINE $7009,$A823; { create a minimal new alias from a target fullpath (optional zone and server name) and return alias record handle } æDT myVariable := NewAliasMinimalFromFullpath(fullpathLength,fullpath,zoneName,serverName,alias); æC æKY ResolveAlias æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION ResolveAlias(fromFile: CanonicalFileSpecPtr;alias: AliasHandle; VAR target: CanonicalFileSpec;VAR wasChanged: BOOLEAN): OSErr; INLINE $7003,$A823; { given an alias handle and fromFile, resolve the alias, update the alias record and return aliased filename and wasChanged flag. } æDT myVariable := ResolveAlias(fromFile,alias,target,wasChanged); æC You use the ResolveAlias function to resolve an alias. FUNCTION ResolveAlias (fromFile: FSSpecPtr; alias: AliasHandle; VAR target: FSSpec; VAR wasChanged: Boolean) : OSErr; If the resolution is successful, ResolveAlias returns the FSSpec record for the target filename through the target parameter, updates the alias record if necessary, and reports whether or not the record was updated through the wasChanged parameter. If the target object is on an unmounted AppleShare volume, ResolveAlias automatically mounts the volume. If the target is on an unmounted, ejectable volume, ResolveAlias displays a switch-disk dialog box. ResolveAlias exits after it finds one acceptable target. The fromFile parameter represents the starting point for a relative search. This parameter can be either NIL or a valid FSSpec record. If fromFile is NIL, ResolveAlias does not perform a relative sesarch. The alias parameter points to the alias record to be resolved and, if necessary, updated. The Target parameter receives the FSSpec record of the target filename. If it updates the alias record, ResolveAlias sets the wasChanged parameter to TRUE. Otherwise, it sets it to FALSE. If the function returns an error code, it sets wasChanged to FALSE. Result codes nsvErr -35 The volume is not mounted fnfErr -43 No target was found paramErr -50 The alias parameter is NIL, or the handle is corrupt æKY SelectAlias æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION SelectAlias(fromFile: CanonicalFileSpecPtr;fileTypeName: Str31; aliasFilter: Boolean;alias: AliasHandle;VAR target: CanonicalFileSpec; VAR wasChanged: BOOLEAN;filterProc: Boolean;yourDataPtr: Ptr): OSErr; INLINE $7004,$A823; { given a fromFile and alias handle, match the alias and return aliased entity. If more than one match is found or no match is found, a dialog box is put up. The user directs his search for the correct alias through this dialog box. } æDT myVariable := SelectAlias(fromFile,fileTypeName,aliasFilter,alias,target,wasChanged,filterProc,yourDataPtr); æC If you want the user to direct the search when an alias record cannot be resolved unambiguously, call the SelectAlias function. FUNCTION SelectAlias (fromFile: FSSpecPtr; fileTypeName: Str31; aliasFilter: ProcPtr; alias: AliasHandle; VAR target: FSSpec; VAR wasChanged: Boolean; filterProc: ProcPtr; callbackPtr: Ptr) : OSErr; If SelectAlias finds a single match for the record pointed to by the alias parameter, it behaves the same way as ResolveAlias. If SelectAlias finds no matches or more than one match for the record, the Alias Manager presents a modal dialog box that allows the user to direct the search and select the target. (See “User-Directed Search” for a description of the dialog box.) The fromFile parameter represents the starting point for a relative search. This parameter can be either NIL or a valid FSSpec. If fromFile is NIL, SelectAlias does not perform a relative search. The fileTypeName string is a descriptive name for the file type of the target object, intended to help the user select the correct target. It appears as part of the title of the dialog box. The aliasFilter parameter points to an optional filter function supplied by your application. The Alias Manager executes this function for each possible match that SelectAlias finds or after three seconds have elapsed without a match. Your filter function returns a Boolean value that determines whether the possible match is to be discarded (TRUE) or displayed (FALSE). It can also terminate the search. The function has three parameters. FUNCTION MySelectAliasFilter (paramBlock: CInfoPBPtr; VAR quitFlag: Boolean; callbackPtr: Ptr) : Boolean The paramBlock parameter points to the catalog information parameter block record (as returned by the File Manager function PBGetCatInfo) of the alias match. The Alias Manager sets this parameter to NIL if it is calling the function to give it the chance to terminate the search. (Do not use this pointer without checking for NIL.) Your filter function sets the quitFlag parameter to terminate the search. The callbackPtr parameter is the same as the SelectAlias input parameter callbackPtr. This parameter allows your filter function to access your global or local data. The alias parameter points to the alias record to be resolved and, if necessary, updated. After the alias is resolved to a single target, the target parameter receives the FSSpec for the target. If it updates the alias record, SelectAlias sets the wasChanged parameter to TRUE. Otherwise, it sets it to FALSE. If the function returns an error code, it sets wasChanged to FALSE. The filterProc parameter points to your application’s optional event-filtering function, to be called by ModalDialog. (SelectAlias calls ModalDialog when it displays the SelectAlias dialog box. For a description of the ModalDialog procedure, see the Dialog Manager chapter of Volume I.) The filterProc parameter is similar to the same parameter in the Standard File Package procedure SFPGetFile. The function pointed to by filterProc must be the same as the one you would pass directly to ModalDialog in its filterProc parameter, except that it takes an additional fourth argument, which is the callbackPtr parameter as passed to the SelectAlias routine. This option allows your filter function to access the value of callbackPtr to retrieve your data. The callbackPtr parameter contains whatever data you specify. Use this parameter to pass information to your filter function. Result codes fnfErr -43 No target was found paramErr -50 target, alias, or both are NIL, or the handle is corrupt userCanceledErr -128 The user canceled the operation æKY GetAliasInfo æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION GetAliasInfo(alias: AliasHandle;index: AliasInfoType;VAR theString: Str63): OSErr; INLINE $7007,$A823; { given an alias handle and an index specifying requested alias information type, return the information from alias record as a string. } æDT myVariable := GetAliasInfo(alias,index,theString); æC You can use the GetAliasInfo function to read information from an alias record. FUNCTION GetAliasInfo (alias: AliasHandle; index: AliasInfoType; VAR theString: Str63 ) : OSErr; GetAliasInfo retrieves the information specified by the index parameter from the record pointed to by the alias parameter and places it in the parameter theString. The alias parameter points to the alias record to be read. The index parameter specifies the kind of information to be retrieved. If index is a positive integer, GetAliasInfo retrieves the parent folder that has the same hierarchical level as the index parameter. You can therefore assemble the names of the target and all of its parent folders by making repeated calls to GetAliasInfo with incrementing index values, starting with a value of 0. When index is greater than the hierarchical level of the root, GetAliasInfo returns an empty string. You can also set index to one of these five values: Constant Value Description asiZoneName -3 If the record represents an object on an AppleShare volume, retrieve the server’s zone name. Otherwise, return an empty string. asiServerName -2 If the record represents an object on an AppleShare volume, retrieve server name. Otherwise, return an empty string. asiVolumeName -1 Return the name of the volume on which the represented object resides. asiAliasName 0 Return the name of the object represented by the record. asiParentName 1 Return the name of the parent folder of the object represented by the record. If the object is a volume, return the volume name. GetAliasInfo places the requested information in the parameter theString. GetAliasInfo returns the information stored in the alias record, which might not be current. Result codes paramErr -50 alias, theString, or both are NIL; the index is less than asiZoneName; or the handle is corrupt æKY MatchAlias æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION MatchAlias(fromFile: CanonicalFileSpecPtr;rulesMask: unsigned long; alias: AliasHandle;VAR aliasCount: INTEGER;aliasList: CanonicalFileSpecListPtr; VAR needsUpdate: BOOLEAN;aliasFilter: Boolean;yourDataPtr: Ptr): OSErr; INLINE $7005,$A823; { Low Level Routines given an alias handle and fromFile, match the alias and return aliased filename(s) and needsUpdate flag } æDT myVariable := MatchAlias(fromFile,rulesMask,alias,aliasCount,aliasList,needsUpdate,aliasFilter,yourDataPtr); æC You use the MatchAlias function to identify a list of possible matches and pass the list through a selection filter. The filter can pass more than one possible match. FUNCTION MatchAlias (fromFile: FSSpecPtr; rulesMask: LongInt; alias: AliasHandle; VAR aliasCount: Integer; aliasList: FSSpecListPtr; VAR needsUpdate: Boolean; aliasFilter: ProcPtr; callbackPtr: Ptr) : OSErr; MatchAlias resolves the alias record pointed to by the alias parameter and returns a list of FSSpec records in the structure pointed to by the aliasList parameter. If it identifies more than one possible target, MatchAlias places in the aliasCount parameter the number of candidates in aliasList. MatchAlias follows the rules specified by the rulesMask parameter. If it resolves the alias to an object other than the one stored in the alias record or if it returns a list of possible candidates, it sets the needsUpdate flag to TRUE. Your application is responsible for calling UpdateAlias if necessary after the target is identified. The fromFile parameter represents the starting point for a relative search. This parameter can be either NIL or a valid FSSpec record. If fromFile is NIL, MatchAlias does not perform a relative search. The rulesMask parameter specifies a set of rules to guide the resolution. Pass the sum of all of the rules you want to invoke. Constant Description kARMmountVol Automatically try to mount the target’s volume if it is not mounted. If this rule is not set, and if the target’s volume is not mounted, MatchAlias returns nsvErr. kARMmultVols Search all mounted volumes. The search begins with the volume on which the target resided when the record was created. kARMsearch Search quickly for the alias, using the fast-search algorithm. kARMsearchMore Search further, using the slow-search algorithm. The further search uses the File Manager function CatSearch to match criteria such as creation date, type, and creator. CatSearch is available only on HFS volumes. When searching MFS volumes or AppleShare volumes running older system software, MatchAlias performs a recursive, indexing search using creation date, type, and creator. If both kARMsearch and kARMsearchMore are set, MatchAlias performs a fast search followed by a slow search. The alias parameter points to the alias record to be resolved. Your application can specify a maximum number of possible matches by setting the aliasCount parameter. MatchAlias sets the aliasCount parameter to the number of entries in the list of possible matches. The aliasList parameter points to the array that holds the results of the search. If MatchAlias resolves the alias to a target whose key information is different, or if it returns a list of possible candidates, it sets the needsUpdate flag to TRUE. Otherwise, it sets it to FALSE. The aliasFilter parameter points to a filter function supplied by your application. The Alias Manager executes this function for each possible match that MatchAlias finds or after three seconds have elapsed without a match. Your filter function returns a Boolean value that determines whether the possible match is discarded (TRUE) or added to the list of possible targets (FALSE). It can also terminate the search. The function has three parameters. FUNCTION MyMatchAliasFilter (paramBlock: CInfoPBPtr; VAR quitFlag: Boolean; callbackPtr: Ptr): Boolean The paramBlock parameter points to the catalog information parameter block record (as returned by the File Manager function PBGetCatInfo) of the alias match. The Alias Manager sets this parameter to NIL if it is calling the function to give it the chance to terminate the search. (Do not use this pointer without checking for NIL.) Your filter function sets the quitFlag parameter to terminate the search. The callbackPtr parameter is the same as the MatchAlias input parameter callbackPtr. This parameter allows your filter function to access your global or local data. The callbackPtr parameter contains whatever data you specify. Use this parameter to pass information to your filter function. Result codes nsvErr -35 The volume is not mounted fnfErr -43 No target was found paramErr -50 target, alias, or both are NIL, or the handle is corrupt userCanceledErr -128 The user canceled the operation æKY UpdateAlias æFp Aliases.p æT FUNCTION æTN A823 æD FUNCTION UpdateAlias(fromFile: CanonicalFileSpecPtr;target: CanonicalFileSpec; alias: AliasHandle;VAR wasChanged: BOOLEAN): OSErr; INLINE $7006,$A823; { given a fromFile-target pair and an alias handle, update the lias record pointed to by alias handle to represent target as the new alias. } æDT myVariable := UpdateAlias(fromFile,target,alias,wasChanged); æC You use the UpdateAlias function to update an alias record. FUNCTION UpdateAlias (fromFile,target: FSSpecPtr; alias: AliasHandle; VAR wasChanged: Boolean) : OSErr; UpdateAlias updates the alias record pointed to by the alias parameter so that it describes the file, folder, or volume specified by the target parameter. UpdateAlias rebuilds the entire alias record. The fromFile parameter represents the starting point for a relative search. This parameter can be either NIL or a pointer to a valid FSSpec record. If fromFile is NIL, the updated alias record does not include relative path information. Specify a value for fromFile only if you want UpdateAlias to record relative path information. The target parameter is the target of the alias record. This parameter must point to a valid canonical file specification record. The alias parameter points to the alias record to be updated. If the newly constructed alias record is exactly the same as the old one, UpdateAlias sets the wasChanged parameter to FALSE. Otherwise, it sets it to TRUE. Check this parameter to determine whether you need to save an updated record. Result codes paramErr -50 target, alias, or both are NIL, or the handle is corrupt æKY AppleEvents.p æKL AEAddEvtToTable AECoerceDesc AECountListElems AECreateAevt AECreateDispatchTable AECreateList AEDeleteIndex AEDeleteKey AEDisposeAEDesc AEDisposeAEList AEGetAddress AEGetArray AEGetDispatchTableRsrc AEGetEventClassAndID AEGetInteractLevel AEGetKeyDesc AEGetKeyPtr AEGetNthDesc AEGetNthPtr AEGetRefCon AEGetTableEntry AEInit AEInteractionAllowed AEInteractWithUser AEProcessAppleEvent AEPutArray AEPutDesc AEPutKeyDesc AEPutKeyPtr AEPutPtr AEQuit AEResetTimer AESend AESetAddressByPSN AESetAddressBySessionID AESetAddressBySignature AESetAddressByTargetID AEWhichAevt AEAddress AEAddressHndl AEAddressPtr AEArrayType AEDesc AEInteractAllowed AEKeyDesc kAEAliasType kAEAlwaysInteract kAEBadListElement kAEBooleanType kAECanInteract kAECanSwitchLayer kAECoercionFail kAECorruptData kAEDataArray kAEDescArray kAEDescNotFound kAEDirectObjectKeyword kAEDontReconnect kAEEventNotFound kAEEventNotInTable kAEFalseType kAEHandleArray kAEHighPriority kAEInteractionWithSelf kAEInteractWithAll kAEInteractWithLocal kAEKeyDescArray kAEListType kAELongType kAENeverInteract kAENoReply kAENormalPriority kAENotAEList kAENotAppleEvent kAENoUserInteraction kAEOpenApplication kAEOpenDocuments kAEPackedArray kAEPrintDocuments kAEQueueReply kAEQuitApplication kAEReplyNotValid kAETimeoutErr kAETrueType kAEUnknownInteract kAEUnknownSendMode KAEWaitCanceled kAEWaitReply kAEWantReceipt kAEWildType kAEWrongDataType kAEWrongVersion kAutoGenerateRefcon kCoreEventClass æKY kAELongType æFp AppleEvents.p æT CONST æD kAELongType = 'long'; æC æKY kAEListType æFp AppleEvents.p æT CONST æD kAEListType = 'list'; æC æKY kAEWildType æFp AppleEvents.p æT CONST æD kAEWildType = '****'; æC æKY kAEBooleanType æFp AppleEvents.p æT CONST æD kAEBooleanType = 'bool'; æC æKY kAETrueType æFp AppleEvents.p æT CONST æD kAETrueType = 'true'; æC æKY kAEFalseType æFp AppleEvents.p æT CONST æD kAEFalseType = 'fals'; æC æKY kAEAliasType æFp AppleEvents.p æT CONST æD kAEAliasType = 'alis'; æC æKY kAEDirectObjectKeyword æFp AppleEvents.p æT CONST æD kAEDirectObjectKeyword = '----'; æC æKY kCoreEventClass æFp AppleEvents.p æT CONST æD kCoreEventClass = 'aevt'; æC æKY kAEOpenApplication æFp AppleEvents.p æT CONST æD kAEOpenApplication = 'oapp'; æC æKY kAEOpenDocuments æFp AppleEvents.p æT CONST æD kAEOpenDocuments = 'odoc'; æC æKY kAEPrintDocuments æFp AppleEvents.p æT CONST æD kAEPrintDocuments = 'pdoc'; æC æKY kAEQuitApplication æFp AppleEvents.p æT CONST æD kAEQuitApplication = 'quit'; æC æKY kAENoReply æFp AppleEvents.p æT CONST æD kAENoReply = $00000001; { Sender doesn't want a reply to event } æC æKY kAEQueueReply æFp AppleEvents.p æT CONST æD kAEQueueReply = $00000002; { Sender wants a reply but won't wait } æC æKY kAEWaitReply æFp AppleEvents.p æT CONST æD kAEWaitReply = $00000003; { Sender wants a reply and will be waiting } æC æKY kAENeverInteract æFp AppleEvents.p æT CONST æD kAENeverInteract = $00000010; { Server should not interact with user } æC æKY kAECanInteract æFp AppleEvents.p æT CONST æD kAECanInteract = $00000020; { Server may try to interact with user } æC æKY kAEAlwaysInteract æFp AppleEvents.p æT CONST æD kAEAlwaysInteract = $00000030; { Server should always interact with user } æC æKY kAECanSwitchLayer æFp AppleEvents.p æT CONST æD kAECanSwitchLayer = $00000040; { Interaction may switch layer } æC æKY kAEDontReconnect æFp AppleEvents.p æT CONST æD kAEDontReconnect = $00000080; { don't reconnect if there is a sessClosedErr } æC æKY kAEWantReceipt æFp AppleEvents.p æT CONST æD kAEWantReceipt = nReturnReceipt; { Send wants a receipt of message } æC æKY kAENormalPriority æFp AppleEvents.p æT CONST æD kAENormalPriority = $00000000; { Post message at the end of event queue } æC æKY kAEHighPriority æFp AppleEvents.p æT CONST æD kAEHighPriority = nAttnMsg; { Post message at the front of the event queue } æC æKY kAutoGenerateRefcon æFp AppleEvents.p æT CONST æD kAutoGenerateRefcon = 0; æC æKY kAEEventNotInTable æFp AppleEvents.p æT CONST æD kAEEventNotInTable = 0; { Passed to the general dispatch proc if the event received was not in the dispatch table } æC æKY kAECoercionFail æFp AppleEvents.p æT CONST æD { Error messages in response to reading and writing buffer contents } kAECoercionFail = -1700; æC æKY kAEDescNotFound æFp AppleEvents.p æT CONST æD kAEDescNotFound = -1701; æC æKY kAECorruptData æFp AppleEvents.p æT CONST æD kAECorruptData = -1702; æC æKY kAEWrongDataType æFp AppleEvents.p æT CONST æD kAEWrongDataType = -1703; æC æKY kAENotAEList æFp AppleEvents.p æT CONST æD kAENotAEList = -1704; æC æKY kAEBadListElement æFp AppleEvents.p æT CONST æD kAEBadListElement = -1705; æC æKY kAEWrongVersion æFp AppleEvents.p æT CONST æD kAEWrongVersion = -1706; æC æKY kAENotAppleEvent æFp AppleEvents.p æT CONST æD kAENotAppleEvent = -1707; æC æKY kAEEventNotFound æFp AppleEvents.p æT CONST æD { Error messages in response to sending/receiving a message } kAEEventNotFound = -1708; { The event isn't in the supplied event table } æC æKY kAEReplyNotValid æFp AppleEvents.p æT CONST æD kAEReplyNotValid = -1709; { AEResetTimer was passed an invalid reply } æC æKY kAEUnknownSendMode æFp AppleEvents.p æT CONST æD kAEUnknownSendMode = -1710; { Mode wasn't NoReply, WaitReply, QueueReply; or Interaction level is unknown } æC æKY KAEWaitCanceled æFp AppleEvents.p æT CONST æD KAEWaitCanceled = -1711; { User cancelled out of wait loop for reply or receipt } æC æKY kAETimeoutErr æFp AppleEvents.p æT CONST æD kAETimeoutErr = -1712; { AppleEvent time out } æC æKY kAENoUserInteraction æFp AppleEvents.p æT CONST æD kAENoUserInteraction = -1713; { no user interaction allowed } æC æKY AEArrayType kAEDataArray kAEPackedArray kAEHandleArray kAEDescArray kAEKeyDescArray æFp AppleEvents.p æT TYPE æD AEArrayType = (kAEDataArray,kAEPackedArray,kAEHandleArray,kAEDescArray, kAEKeyDescArray); æC æKY AEInteractAllowed kAEUnknownInteract kAEInteractionWithSelf kAEInteractWithLocal kAEInteractWithAll æFp AppleEvents.p æT TYPE æD AEInteractAllowed = (kAEUnknownInteract,kAEInteractionWithSelf,kAEInteractWithLocal, kAEInteractWithAll); æC æKY AEAddress AEAddressPtr AEAddressHndl æFp AppleEvents.p æT RECORD æD AEAddressPtr = ^AEAddress; AEAddressHndl = ^AEAddressPtr; AEAddress = RECORD CASE addressKind: LONGINT OF receiverIDisPSN: (receiverIDasPSN: ProcessSerialNumber); receiverIDisSignature: (receiverIDasSig: OSType); receiverIDisSessionID: (receiverIDasSess: LONGINT); receiverIDisTargetID: (receiverIDasTargetID: TargetID); END; æC æKY AEDesc æFp AppleEvents.p æT RECORD æD AEDesc = RECORD descriptorType: DescType; CASE BOOLEAN OF false: (asDataHdl: Handle); true: (asAEList: AEList); END; æC æKY AEKeyDesc æFp AppleEvents.p æT RECORD æD AEKeyDesc = RECORD descKey: KeyWord; descContent: AEDesc; END; æC æKY AEInit æFp AppleEvents.p æT FUNCTION æD FUNCTION AEInit(dispatchProc: ProcPtr;coercionProc: ProcPtr;nonAevtHandler: ProcPtr): OSErr; æDT myVariable := AEInit(dispatchProc,coercionProc,nonAevtHandler); æC æKY AEQuit æFp AppleEvents.p æT PROCEDURE æD PROCEDURE AEQuit; æDT AEQuit; æC æKY AEPutPtr æFp AppleEvents.p æT FUNCTION æD FUNCTION AEPutPtr(theList: AEList;index: LONGINT;typeCode: DescType;dataPtr: Ptr; dataSize: LONGINT): OSErr; æDT myVariable := AEPutPtr(theList,index,typeCode,dataPtr,dataSize); æC æKY AEPutDesc æFp AppleEvents.p æT FUNCTION æD FUNCTION AEPutDesc(theList: AEList;index: LONGINT;theDesc: AEDesc): OSErr; æDT myVariable := AEPutDesc(theList,index,theDesc); æC æKY AEPutKeyPtr æFp AppleEvents.p æT FUNCTION æD FUNCTION AEPutKeyPtr(theList: AEList;key: KeyWord;typeCode: DescType;dataPtr: Ptr; dataSize: LONGINT): OSErr; æDT myVariable := AEPutKeyPtr(theList,key,typeCode,dataPtr,dataSize); æC æKY AEPutKeyDesc æFp AppleEvents.p æT FUNCTION æD FUNCTION AEPutKeyDesc(theList: AEList;key: KeyWord;theDesc: AEDesc): OSErr; æDT myVariable := AEPutKeyDesc(theList,key,theDesc); æC æKY AEGetNthPtr æFp AppleEvents.p æT FUNCTION æD FUNCTION AEGetNthPtr(theList: AEList;index: LONGINT;desiredType: DescType; VAR key: KeyWord;VAR typeCode: DescType;dataPtr: Ptr;maxSize: LONGINT; VAR actualSize: LONGINT): OSErr; æDT myVariable := AEGetNthPtr(theList,index,desiredType,key,typeCode,dataPtr, maxSize,actualSize); æC æKY AEGetNthDesc æFp AppleEvents.p æT FUNCTION æD FUNCTION AEGetNthDesc(theList: AEList;index: LONGINT;desiredType: DescType; VAR key: KeyWord;VAR theDesc: AEDesc): OSErr; æDT myVariable := AEGetNthDesc(theList,index,desiredType,key,theDesc); æC æKY AEGetKeyPtr æFp AppleEvents.p æT FUNCTION æD FUNCTION AEGetKeyPtr(theList: AEList;key: KeyWord;desiredType: DescType; VAR typeCode: DescType;dataPtr: Ptr;maxSize: LONGINT;VAR actualSize: LONGINT): OSErr; æDT myVariable := AEGetKeyPtr(theList,key,desiredType,typeCode,dataPtr,maxSize,actualSize); æC æKY AEGetKeyDesc æFp AppleEvents.p æT FUNCTION æD FUNCTION AEGetKeyDesc(theList: AEList;key: KeyWord;desiredType: DescType; VAR theDesc: AEDesc): OSErr; æDT myVariable := AEGetKeyDesc(theList,key,desiredType,theDesc); æC æKY AEGetArray æFp AppleEvents.p æT FUNCTION æD FUNCTION AEGetArray(theList: AEList;arrayType: AEArrayType;arrayPtr: Ptr; bufSize: LONGINT;VAR elemType: DescType;VAR elemSize: LONGINT;VAR itemCount: LONGINT): OSErr; æDT myVariable := AEGetArray(theList,arrayType,arrayPtr,bufSize,elemType,elemSize,itemCount); æC æKY AEPutArray æFp AppleEvents.p æT FUNCTION æD FUNCTION AEPutArray(theList: AEList;arrayType: AEArrayType;arrayPtr: Ptr; elemType: DescType;elemSize: LONGINT;itemCount: LONGINT): OSErr; æDT myVariable := AEPutArray(theList,arrayType,arrayPtr,elemType,elemSize,itemCount); æC æKY AEDeleteIndex æFp AppleEvents.p æT FUNCTION æD FUNCTION AEDeleteIndex(theList: AEList;index: LONGINT): OSErr; æDT myVariable := AEDeleteIndex(theList,index); æC æKY AEDeleteKey æFp AppleEvents.p æT FUNCTION æD FUNCTION AEDeleteKey(theList: AEList;key: KeyWord): OSErr; æDT myVariable := AEDeleteKey(theList,key); æC æKY AECoerceDesc æFp AppleEvents.p æT FUNCTION æD FUNCTION AECoerceDesc(desc: AEDesc;toType: DescType;VAR result: AEDesc): OSErr; æDT myVariable := AECoerceDesc(desc,toType,result); æC æKY AEDisposeAEList æFp AppleEvents.p æT PROCEDURE æD PROCEDURE AEDisposeAEList(theArg: AEList); æDT AEDisposeAEList(theArg); æC æKY AEDisposeAEDesc æFp AppleEvents.p æT PROCEDURE æD PROCEDURE AEDisposeAEDesc(theArg: AEDesc); æDT AEDisposeAEDesc(theArg); æC æKY AECreateAevt æFp AppleEvents.p æT FUNCTION æD FUNCTION AECreateAevt(theEventClass: EventClass;theEventID: EventID;target: AEAdress; theRefCon: LONGINT;VAR result: AEList): OSErr; æDT myVariable := AECreateAevt(theEventClass,theEventID,target,theRefCon,result); æC æKY AEGetEventClassAndID æFp AppleEvents.p æT PROCEDURE æD { Extract the event class and id from the specified message } PROCEDURE AEGetEventClassAndID(theAevt: AEList;VAR theEventClass: EventClass; VAR theEventID: EventID); æDT AEGetEventClassAndID(theAevt,theEventClass,theEventID); æC æKY AEGetRefCon æFp AppleEvents.p æT PROCEDURE æD { Extract the event class and id from the specified message } PROCEDURE AEGetRefCon(theAevt: AEList;VAR refCon: LONGINT); æDT AEGetRefCon(theAevt,refCon); æC æKY AEGetAddress æFp AppleEvents.p æT PROCEDURE æD { Extract the address from the specified message } PROCEDURE AEGetAddress(theAevt: AEList;VAR address: AEAddress); æDT AEGetAddress(theAevt,address); æC æKY AECreateList æFp AppleEvents.p æT FUNCTION æD FUNCTION AECreateList(factoringPtr: Ptr;factoredSize: LONGINT;isRecord: BOOLEAN; VAR resultList: AEDesc): OSErr; æDT myVariable := AECreateList(factoringPtr,factoredSize,isRecord,resultList); æC æKY AECountListElems æFp AppleEvents.p æT FUNCTION æD FUNCTION AECountListElems(theList: AEList): LONGINT; æDT myVariable := AECountListElems(theList); æC æKY AESend æFp AppleEvents.p æT FUNCTION æD FUNCTION AESend(theList: AEList;VAR theReply: AEList;sendMode: LONGINT; sendPriority: INTEGER;timeOut: LONGINT;idleProc: ProcPtr): OSErr; æDT myVariable := AESend(theList,theReply,sendMode,sendPriority,timeOut,idleProc); æC æKY AEResetTimer æFp AppleEvents.p æT FUNCTION æD { Convience routine. Create and send a 'wait' message from the information in the reply. } FUNCTION AEResetTimer(reply: AEList): OSErr; æDT myVariable := AEResetTimer(reply); æC æKY AESetAddressByPSN æFp AppleEvents.p æT PROCEDURE æD { Fill theAddressObject as receiverIDisPSN } PROCEDURE AESetAddressByPSN(thePSN: ProcessSerialNumber;VAR theAddress: AEAdress); æDT AESetAddressByPSN(thePSN,theAddress); æC æKY AESetAddressBySignature æFp AppleEvents.p æT PROCEDURE æD { Fill theAddressObject as receiverIDisSignature } PROCEDURE AESetAddressBySignature(theSig: OSType;VAR theAddress: AEAddress); æDT AESetAddressBySignature(theSig,theAddress); æC æKY AESetAddressBySessionID æFp AppleEvents.p æT PROCEDURE æD { Fill theAddressObject as receiverIDisSessionID } PROCEDURE AESetAddressBySessionID(theSessionID: LONGINT;VAR theAddress: AEAddress); æDT AESetAddressBySessionID(theSessionID,theAddress); æC æKY AESetAddressByTargetID æFp AppleEvents.p æT PROCEDURE æD { Fill theAddressObject as receiverIDisTargetID } PROCEDURE AESetAddressByTargetID(theTargetID: TargetID;VAR theAddress: AEAddress); æDT AESetAddressByTargetID(theTargetID,theAddress); æC æKY AEProcessAppleEvent æFp AppleEvents.p æT FUNCTION æD FUNCTION AEProcessAppleEvent(eventRec: EventRecord): OSErr; æDT myVariable := AEProcessAppleEvent(eventRec); æC æKY AEGetDispatchTableRsrc æFp AppleEvents.p æT FUNCTION æD { Load an event table from a 'AEDF' resource. This of course will only be of use to applications using a general dispatch routine rather than doing a direct dispatch to a handler. } FUNCTION AEGetDispatchTableRsrc(tableID: INTEGER): OSErr; æDT myVariable := AEGetDispatchTableRsrc(tableID); æC the specified string is drawn. æKY AECreateDispatchTable æFp AppleEvents.p æT FUNCTION æD { Create an event table with one memory manager call for the number of events specified. If more events are added to the table with AESetupEventTable, the table will be grown automatically. } FUNCTION AECreateDispatchTable(numEntries: INTEGER): OSErr; æDT myVariable := AECreateDispatchTable(numEntries); æC æKY AEAddEvtToTable æFp AppleEvents.p æT FUNCTION æD { Add a single event to the table, expanding if necessary. } FUNCTION AEAddEvtToTable(theEventClass: EventClass;theEventID: EventID; value: LONGINT): OSErr; æDT myVariable := AEAddEvtToTable(theEventClass,theEventID,value); æC æKY AEGetTableEntry æFp AppleEvents.p æT FUNCTION æD { returns the value of the specified event in theValue. kAEEventNotFound if not found. } FUNCTION AEGetTableEntry(theEventClass: EventClass;theEventID: EventID; VAR theValue: LONGINT): OSErr; æDT myVariable := AEGetTableEntry(theEventClass,theEventID,theValue); æC æKY AEInteractWithUser æFp AppleEvents.p æT FUNCTION æD FUNCTION AEInteractWithUser(timeOut: LONGINT;nmReqPtr: QElemPtr): OSErr; æDT myVariable := AEInteractWithUser(timeOut,nmReqPtr); æC æKY AEGetInteractLevel æFp AppleEvents.p æT FUNCTION æD { returns kAENeverInteract, kAECanInteract or kAEAlwaysInteract } FUNCTION AEGetInteractLevel(theAevt: AEList): INTEGER; æDT myVariable := AEGetInteractLevel(theAevt); æC æKY AEInteractionAllowed æFp AppleEvents.p æT FUNCTION æD FUNCTION AEInteractionAllowed(theLevel: AEInteractAllowed): AEInteractAllowed; æDT myVariable := AEInteractionAllowed(theLevel); æC æKY AEWhichAevt æFp AppleEvents.p æT FUNCTION æD FUNCTION AEWhichAevt: AEList; æDT myVariable := AEWhichAevt; æC æKY AppleTalk.p æKL AFPCommand ASPAbortOS ASPCloseAll ASPCloseSession ASPGetParms ASPGetStatus ASPOpenSession ASPUserCommand ASPUserWrite ATPAddRsp ATPCloseSocket ATPGetRequest ATPLoad ATPOpenSocket ATPReqCancel ATPRequest ATPResponse ATPRspCancel ATPSndRequest ATPSndRsp ATPUnload BuildBDS BuildDDPwds BuildLAPwds DDPCloseSocket DDPOpenSocket DDPRdCancel DDPRead DDPWrite GetBridgeAddress GetLocalZones GetMyZone GetNodeAddress GetZoneList IsATPOpen IsMPPOpen LAPCloseProtocol LAPOpenProtocol LAPRdCancel LAPRead LAPWrite MPPClose MPPOpen NBPConfirm NBPExtract NBPLoad NBPLookup NBPRegister NBPRemove NBPSetEntity NBPSetNTE NBPUnload OpenXPP PAddResponse PATalkClosePrep PAttachPH PCancelATalkClosePrep PCloseATPSkt PCloseSkt PConfirmName PDetachPH PGetAppleTalkInfo PGetRequest PKillAllGetReq PKillGetReq PKillNBP PKillSendReq PLookupName PNSendRequest POpenATPSkt POpenSkt PRegisterName PRelRspCB PRelTCB PRemoveName PSendRequest PSendResponse PSetSelfSend PWriteDDP PWriteLAP RemoveHdlBlocks ABByte ABCallType ABProtoType ABRecHandle ABRecPtr ABusRecord AddrBlock afpAddAPPL afpAddCmt afpAddIcon afpByteRangeLock AFPCommandBlock afpContLogin afpCopyFile afpDelete afpDirClose afpDirCreate afpDTClose afpDTOpen afpEnumerate afpFileCreate afpFlush afpForkClose afpForkFlush afpGetAPPL afpGetCmt afpGetDirParms afpGetFileParms afpGetFlDrParms afpGetForkParms afpGetIcon afpGetSInfo afpGetSParms afpGetVolParms afpGtIcnInfo afpLogin afpLogout afpMapID afpMapName afpMove afpOpenDir afpOpenFork afpOpenVol afpRead afpRename afpRmvAPPL afpRmvCmt afpSetDirParms afpSetFileParms afpSetFlDrParms afpSetForkParms afpSetVolParms afpVolClose afpWrite atpEOMvalue ATPParamBlock ATPPBPtr atpProto atpSendChkvalue atpSize atpSTSvalue atpTIDValidvalue atpXOvalue ATQEntry BDSElement BDSPtr BDSType BitMapType ddpProto ddpSize EntityName EntityPtr LAPAdrBlock LAPMgrCall LAPMgrPtr lapProto lapSize MPPParamBlock MPPParmType MPPPBPtr NamesTableEntry nbpProto nbpSize RetransType scbMemSize Str32 tATPAddRsp tATPGetRequest tATPRequest tATPResponse tATPSdRsp tATPSndRequest tDDPRead tDDPWrite tLAPRead tLAPWrite tNBPConfirm tNBPLookup tNBPRegister WDSElement XPPEndPrmType xppFlagClr xppFlagSet xppLoadedBit XPPParamBlock XPPParmBlkPtr XPPPrmBlkType xppRefNum XPPSubPrmType xppUnitNum æKY afpByteRangeLock æFp AppleTalk.p æT CONST æD afpByteRangeLock = 1; {AFPCall command codes} æC æKY afpVolClose æFp AppleTalk.p æT CONST æD afpVolClose = 2; {AFPCall command codes} æC æKY afpDirClose æFp AppleTalk.p æT CONST æD afpDirClose = 3; {AFPCall command codes} æC æKY afpForkClose æFp AppleTalk.p æT CONST æD afpForkClose = 4; {AFPCall command codes} æC æKY afpCopyFile æFp AppleTalk.p æT CONST æD afpCopyFile = 5; {AFPCall command codes} æC æKY afpDirCreate æFp AppleTalk.p æT CONST æD afpDirCreate = 6; {AFPCall command codes} æC æKY afpFileCreate æFp AppleTalk.p æT CONST æD afpFileCreate = 7; {AFPCall command codes} æC æKY afpDelete æFp AppleTalk.p æT CONST æD afpDelete = 8; {AFPCall command codes} æC æKY afpEnumerate æFp AppleTalk.p æT CONST æD afpEnumerate = 9; {AFPCall command codes} æC æKY afpFlush æFp AppleTalk.p æT CONST æD afpFlush = 10; {AFPCall command codes} æC æKY afpForkFlush æFp AppleTalk.p æT CONST æD afpForkFlush = 11; {AFPCall command codes} æC æKY afpGetDirParms æFp AppleTalk.p æT CONST æD afpGetDirParms = 12; {AFPCall command codes} æC æKY afpGetFileParms æFp AppleTalk.p æT CONST æD afpGetFileParms = 13; {AFPCall command codes} æC æKY afpGetForkParms æFp AppleTalk.p æT CONST æD afpGetForkParms = 14; {AFPCall command codes} æC æKY afpGetSInfo æFp AppleTalk.p æT CONST æD afpGetSInfo = 15; {AFPCall command codes} æC æKY afpGetSParms æFp AppleTalk.p æT CONST æD afpGetSParms = 16; {AFPCall command codes} æC æKY afpGetVolParms æFp AppleTalk.p æT CONST æD afpGetVolParms = 17; {AFPCall command codes} æC æKY afpLogin æFp AppleTalk.p æT CONST æD afpLogin = 18; {AFPCall command codes} æC æKY afpContLogin æFp AppleTalk.p æT CONST æD afpContLogin = 19; {AFPCall command codes} æC æKY afpLogout æFp AppleTalk.p æT CONST æD afpLogout = 20; {AFPCall command codes} æC æKY afpMapID æFp AppleTalk.p æT CONST æD afpMapID = 21; {AFPCall command codes} æC æKY afpMapName æFp AppleTalk.p æT CONST æD afpMapName = 22; {AFPCall command codes} æC æKY afpMove æFp AppleTalk.p æT CONST æD afpMove = 23; {AFPCall command codes} æC æKY afpOpenVol æFp AppleTalk.p æT CONST æD afpOpenVol = 24; {AFPCall command codes} æC æKY afpOpenDir æFp AppleTalk.p æT CONST æD afpOpenDir = 25; {AFPCall command codes} æC æKY afpOpenFork æFp AppleTalk.p æT CONST æD afpOpenFork = 26; {AFPCall command codes} æC æKY afpRead æFp AppleTalk.p æT CONST æD afpRead = 27; {AFPCall command codes} æC æKY afpRename æFp AppleTalk.p æT CONST æD afpRename = 28; {AFPCall command codes} æC æKY afpSetDirParms æFp AppleTalk.p æT CONST æD afpSetDirParms = 29; {AFPCall command codes} æC æKY afpSetFileParms æFp AppleTalk.p æT CONST æD afpSetFileParms = 30; {AFPCall command codes} æC æKY afpSetForkParms æFp AppleTalk.p æT CONST æD afpSetForkParms = 31; {AFPCall command codes} æC æKY afpSetVolParms æFp AppleTalk.p æT CONST æD afpSetVolParms = 32; {AFPCall command codes} æC æKY afpWrite æFp AppleTalk.p æT CONST æD afpWrite = 33; {AFPCall command codes} æC æKY afpGetFlDrParms æFp AppleTalk.p æT CONST æD afpGetFlDrParms = 34; {AFPCall command codes} æC æKY afpSetFlDrParms æFp AppleTalk.p æT CONST æD afpSetFlDrParms = 35; {AFPCall command codes} æC æKY afpDTOpen æFp AppleTalk.p æT CONST æD afpDTOpen = 48; {AFPCall command codes} æC æKY afpDTClose æFp AppleTalk.p æT CONST æD afpDTClose = 49; {AFPCall command codes} æC æKY afpGetIcon æFp AppleTalk.p æT CONST æD afpGetIcon = 51; {AFPCall command codes} æC æKY afpGtIcnInfo æFp AppleTalk.p æT CONST æD afpGtIcnInfo = 52; {AFPCall command codes} æC æKY afpAddAPPL æFp AppleTalk.p æT CONST æD afpAddAPPL = 53; {AFPCall command codes} æC æKY afpRmvAPPL æFp AppleTalk.p æT CONST æD afpRmvAPPL = 54; {AFPCall command codes} æC æKY afpGetAPPL æFp AppleTalk.p æT CONST æD afpGetAPPL = 55; {AFPCall command codes} æC æKY afpAddCmt æFp AppleTalk.p æT CONST æD afpAddCmt = 56; {AFPCall command codes} æC æKY afpRmvCmt æFp AppleTalk.p æT CONST æD afpRmvCmt = 57; {AFPCall command codes} æC æKY afpGetCmt æFp AppleTalk.p æT CONST æD afpGetCmt = 58; {AFPCall command codes} æC æKY afpAddIcon æFp AppleTalk.p æT CONST æD afpAddIcon = 192; {Special code for ASP Write commands} æC æKY xppLoadedBit æFp AppleTalk.p æT CONST æD xppLoadedBit = 5; { XPP bit in PortBUse } æC æKY xppUnitNum æFp AppleTalk.p æT CONST æD xppUnitNum = 40; {Unit number for XPP (old ROMs) } æC æKY xppRefNum æFp AppleTalk.p æT CONST æD xppRefNum = -41; {.XPP reference number } æC æKY scbMemSize æFp AppleTalk.p æT CONST æD scbMemSize = 192; {Size of memory for SCB } æC æKY xppFlagClr æFp AppleTalk.p æT CONST æD xppFlagClr = 0; {Cs for AFPCommandBlock } æC æKY xppFlagSet æFp AppleTalk.p æT CONST æD xppFlagSet = 128; {StartEndFlag & NewLineFlag fields. } æC æKY lapSize æFp AppleTalk.p æT CONST æD lapSize = 20; æC æKY ddpSize æFp AppleTalk.p æT CONST æD ddpSize = 26; æC æKY nbpSize æFp AppleTalk.p æT CONST æD nbpSize = 26; æC æKY atpSize æFp AppleTalk.p æT CONST æD atpSize = 56; æC æKY atpXOvalue æFp AppleTalk.p æT CONST æD atpXOvalue = 32; {ATP exactly-once bit } æC æKY atpEOMvalue æFp AppleTalk.p æT CONST æD atpEOMvalue = 16; {ATP End-Of-Message bit } æC æKY atpSTSvalue æFp AppleTalk.p æT CONST æD atpSTSvalue = 8; {ATP Send-Transmission-Status bit } æC æKY atpTIDValidvalue æFp AppleTalk.p æT CONST æD atpTIDValidvalue = 2; {ATP trans. ID valid bit } æC æKY atpSendChkvalue æFp AppleTalk.p æT CONST æD atpSendChkvalue = 1; {ATP send checksum bit } æC æKY LAPMgrPtr æFp AppleTalk.p æT CONST æD LAPMgrPtr = $B18; {Entry point for LAP Manager} æC æKY LAPMgrCall æFp AppleTalk.p æT CONST æD LAPMgrCall = 2; {Offset to LAP routines} æC æKY ABCallType tLAPRead tLAPWrite tDDPRead tDDPWrite tNBPLookup tNBPConfirm tNBPRegister tATPSndRequest tATPGetRequest tATPSdRsp tATPAddRsp tATPRequest tATPResponse æFp AppleTalk.p æT TYPE æD ABCallType = (tLAPRead,tLAPWrite,tDDPRead,tDDPWrite,tNBPLookup,tNBPConfirm, tNBPRegister,tATPSndRequest,tATPGetRequest,tATPSdRsp,tATPAddRsp,tATPRequest, tATPResponse); æC æKY ABProtoType lapProto ddpProto nbpProto atpProto æFp AppleTalk.p æT TYPE æD ABProtoType = (lapProto,ddpProto,nbpProto,atpProto); æC æKY Str32 æFp AppleTalk.p æT RECORD æD Str32 = String[32]; æC æKY ABByte æFp AppleTalk.p æT RECORD æD ABByte = 1..127; æC æKY LAPAdrBlock æFp AppleTalk.p æT RECORD æD LAPAdrBlock = PACKED RECORD dstNodeID: Byte; srcNodeID: Byte; lapProtType: ABByte; END; æC æKY ATQEntry æFp AppleTalk.p æT RECORD æD ATQEntry = ^ATQEntry; ATQEntry = PACKED RECORD qLink: QElemPtr; {next queue entry} qType: Integer; {queue type} CallAddr: ProcPtr; {Pointer to your routine} END; æC æKY AddrBlock æFp AppleTalk.p æT RECORD æD AddrBlock = PACKED RECORD aNet: INTEGER; aNode: Byte; aSocket: Byte; END; æC æKY EntityName EntityPtr æFp AppleTalk.p æT RECORD æD EntityPtr = ^EntityName; EntityName = RECORD objStr: Str32; typeStr: Str32; zoneStr: Str32; END; { Real definition of EntityName is 3 PACKED strings of any length (32 is just an example). No offests for Asm since each String address must be calculated by adding length byte to last string ptr. In Pascal, String(32) will be 34 bytes long since fields never start on an odd byte unless they are only a byte long. So this will generate correct looking interfaces for Pascal and C, but they will not be the same, which is OK since they are not used. } æC { Real definition of EntityName is 3 PACKED strings of any length (32 is just an example). No offsets for Asm since each String address must be calculated by adding length byte to last string ptr. In Pascal, String(32) will be 34 bytes long since fields never start on an odd byte unless they are only a byte long. So this will generate correct looking interfaces for Pascal and C, but they will not be the same, which is OK since they are not used. } æKY RetransType æFp AppleTalk.p æT RECORD æD RetransType = PACKED RECORD retransInterval: Byte; retransCount: Byte; END; æC æKY BDSElement æFp AppleTalk.p æT RECORD æD BDSElement = RECORD buffSize: INTEGER; buffPtr: Ptr; dataSize: INTEGER; userBytes: LONGINT; END; æC æKY BDSType BDSPtr æFp AppleTalk.p æT RECORD æD BDSPtr = ^BDSType; BDSType = ARRAY [0..7] OF BDSElement; æC æKY BitMapType æFp AppleTalk.p æT RECORD æD BitMapType = PACKED ARRAY [0..7] OF BOOLEAN; æC æKY ABusRecord ABRecPtr ABRecHandle æFp AppleTalk.p æT RECORD æD ABRecPtr = ^ABusRecord; ABRecHandle = ^ABRecPtr; ABusRecord = RECORD abOpcode: ABCallType; abResult: INTEGER; abUserReference: LONGINT; CASE ABProtoType OF lapProto: (lapAddress: LAPAdrBlock; lapReqCount: INTEGER; lapActCount: INTEGER; lapDataPtr: Ptr); ddpProto: (ddpType: Byte; ddpSocket: Byte; ddpAddress: AddrBlock; ddpReqCount: INTEGER; ddpActCount: INTEGER; ddpDataPtr: Ptr; ddpNodeID: Byte); nbpProto: (nbpEntityPtr: EntityPtr; nbpBufPtr: Ptr; nbpBufSize: INTEGER; nbpDataField: INTEGER; nbpAddress: AddrBlock; nbpRetransmitInfo: RetransType); atpProto: (atpSocket: Byte; atpAddress: AddrBlock; atpReqCount: INTEGER; atpDataPtr: Ptr; atpRspBDSPtr: BDSPtr; atpBitmap: BitMapType; atpTransID: INTEGER; atpActCount: INTEGER; atpUserData: LONGINT; atpXO: BOOLEAN; atpEOM: BOOLEAN; atpTimeOut: Byte; atpRetries: Byte; atpNumBufs: Byte; atpNumRsp: Byte; atpBDSSize: Byte; atpRspUData: LONGINT; atpRspBuf: Ptr; atpRspSize: INTEGER); END; æC _______________________________________________________________________________ »CALLING THE APPLETALK MANAGER FROM PASCAL _______________________________________________________________________________ This section discusses how to use the AppleTalk Manager from Pascal. Equivalent assembly-language information is given in the “Calling the AppleTalk Manager from Assembly Language” section. You can execute many AppleTalk Manager routines either synchronously (meaning that the application can’t continue until the routine is completed) or asynchronously (meaning that the application is free to perform other tasks while the routine is being executed). When an application calls an AppleTalk Manager routine asynchronously, an I/O request is placed in the appropriate driver’s I/O queue, and control returns to the calling program—possibly even before the actual I/O is completed. Requests are taken from the queue one at a time, and processed; meanwhile, the calling program is free to work on other things. The routines that can be executed asynchronously contain a Boolean parameter called async. If async is TRUE, the call is executed asynchronously; otherwise the call is executed synchronously. Every time an asynchronous routine call is completed, the AppleTalk Manager posts a network event. The message field of the event record will contain a handle to the parameter block that was used to make that call. Most AppleTalk Manager routines return an integer result code of type OSErr. Each routine description lists all of the applicable result codes generated by the AppleTalk Manager, along with a short description of what the result code means. Lengthier explanations of all the result codes can be found in the summary at the end of the chapter. Result codes from other parts of the Operating System may also be returned. (See Appendix A for a list of all result codes.) Many Pascal calls to the AppleTalk Manager require information passed in a parameter block of type ABusRecord. The exact content of an ABusRecord depends on the protocol being called: TYPE ABProtoType = (lapProto,ddpProto,nbpProto,atpProto); ABusRecord = RECORD abOpcode: ABCallType; {type of call} abResult: INTEGER; {result code} abUserReference: LONGINT; {for your use} CASE ABProtoType OF lapProto: . . . {ALAP parameters} ddpProto: . . . {DDP parameters} nbpProto: . . . {NBP parameters} atpProto: . . . {ATP parameters} END; END; ABRecPtr = ^ABusRecord; ABRecHandle = ^ABRecPtr; The value of the abOpcode field is inserted by the AppleTalk Manager when the call is made, and is always a member of the following set: TYPE ABCallType = (tLAPRead,tLAPWrite,tDDPRead,tDDPWrite,tNBPLookup, tNBPConfirm,tNBPRegister,tATPSndRequest, tATPGetRequest,tATPSdRsp,tATPAddRsp,tATPRequest, tATPRespond); The abUserReference field is available for use by the calling program in any way it wants. This field isn’t used by the AppleTalk Manager routines or drivers. The size of an ABusRecord data structure in bytes is given by one of the following constants: CONST lapSize = 20; ddpSize = 26; nbpSize = 26; atpSize = 56; Variables of type ABusRecord must be allocated in the heap with Memory Manager NewHandle calls. For example: myABRecord := ABRecHandle(NewHandle(ddpSize)) Warning: These Memory Manager calls can’t be made inside interrupts. Routines that are executed asynchronously return control to the calling program with the result code noErr as soon as the call is placed in the driver’s I/O queue. This isn’t an indication of successful call completion; it simply indicates that the call was successfully queued to the appropriate driver. To determine when the call is actually completed, you can either check for a network event or poll the abResult field of the call’s ABusRecord. The abResult field, set to 1 when the call is made, receives the actual result code upon completion of the call. Warning: A data structure of type ABusRecord is often used by the AppleTalk Manager during an asynchronous call, and so is locked by the AppleTalk Manager. Don’t attempt to unlock or use such a variable. Each routine description includes a list of the ABusRecord fields affected by the routine. The arrow next to each field name indicates whether it’s an input, output, or input/output parameter: Arrow Meaning --> Parameter is passed to the routine <-- Parameter is returned by the routine <-> Parameter is passed to and returned by the routine æKY AFPCommandBlock æFp AppleTalk.p æT RECORD æD AFPCommandBlock = PACKED RECORD cmdByte: Byte; startEndFlag: Byte; forkRefNum: INTEGER; rwOffset: LONGINT; reqCount: LONGINT; newLineFlag: Byte; newLineChar: CHAR; END; æC æKY WDSElement æFp AppleTalk.p æT RECORD æD WDSElement = RECORD entryLength: INTEGER; entryPtr: Ptr; END; æC æKY NamesTableEntry æFp AppleTalk.p æT RECORD æD NamesTableEntry = RECORD qLink: QElemPtr; nteAddress: AddrBlock; nteData: PACKED ARRAY [1..100] OF CHAR; END; æC æKY MPPParmType æFp AppleTalk.p æT RECORD æD MPPParmType = (LAPWriteParm,AttachPHParm,DetachPHParm,OpenSktParm,CloseSktParm, WriteDDPParm,OpenATPSktParm,CloseATPSktParm,SendRequestParm,GetRequestParm, SendResponseParm,AddResponseParm,RelTCBParm,RelRspCBParm,RegisterNameParm, LookupNameParm,ConfirmNameParm,RemoveNameParm,SetSelfSendParm,NSendRequestParm, KillSendReqParm,KillGetReqParm,KillNBPParm,GetAppleTalkInfoParm,KillAllGetReqParm, ATalkClosePrepParm,CancelATalkClosePrepParm); æC æKY MPPParamBlock MPPPBPtr æFp AppleTalk.p æT RECORD æD MPPPBPtr = ^MPPParamBlock; MPPParamBlock = PACKED RECORD qLink: QElemPtr; {->Write Data Structure} qType: INTEGER; {queue type} ioTrap: INTEGER; {routine trap} ioCmdAddr: Ptr; {routine address} ioCompletion: ProcPtr; {completion routine} ioResult: OSErr; {result code} ioNamePtr: StringPtr; {->filename} ioVRefNum: INTEGER; {volume reference or drive number} ioRefNum: INTEGER; {driver reference number} csCode: INTEGER; {call command code AUTOMATICALLY set} CASE MPPParmType OF LAPWriteParm: (filler0: INTEGER; wdsPointer: Ptr); {->Write Data Structure} AttachPHParm,DetachPHParm: (protType: Byte; {ALAP Protocol Type} filler1: Byte; handler: Ptr); {->protocol handler routine} OpenSktParm,CloseSktParm,WriteDDPParm: (socket: Byte; {socket number} checksumFlag: Byte; {checksum flag} listener: Ptr); {->socket listener routine} RegisterNameParm,LookupNameParm,ConfirmNameParm,RemoveNameParm: (interval: Byte; {retry interval} count: Byte; {retry count} entityPtr: Ptr; {->names table element or ->entity name} CASE MPPParmType OF RegisterNameParm: (verifyFlag: Byte; {set if verify needed} filler3: Byte); LookupNameParm: (retBuffPtr: Ptr; {->return buffer} retBuffSize: INTEGER; {return buffer size} maxToGet: INTEGER; {matches to get} numGotten: INTEGER); {matched gotten} ConfirmNameParm: (confirmAddr: AddrBlock; {->entity} newSocket: Byte; {socket number} filler4: Byte)); SetSelfSendParm: (newSelfFlag: Byte; {self-send toggle flag} oldSelfFlag: Byte); {previous self-send state} KillNBPParm: (nKillQEl: Ptr); {ptr to Q element to cancel} GetAppleTalkInfoParm: (version: Integer; {requested info version} varsPtr: Ptr; {pointer to well known MPP vars} DCEPtr: Ptr; {pointer to MPP DCE} portID: Integer; {port number [0..7]} configuration: LONGINT; {32-bit configuration word} selfSend: Integer; {non zero if SelfSend enabled} netLo: Integer; {low value of network range} netHi: Integer; {high value of network range} ourAddr: LONGINT; {our 24-bit AppleTalk address} routerAddr: LONGINT; {24-bit address of (last) router} numOfPHs: Integer; {max. number of protocol handlers} numOfSkts: Integer; {max. number of static sockets} numNBPEs: Integer; {max. concurrent NBP requests} nTQueue: Ptr; {pointer to registered name queue} LAlength: Integer; {length in bytes of data link addr} linkAddr: Ptr; {data link address returned} zoneName: Ptr); {zone name returned} ATalkClosePrepParm, CancelATalkClosePrepParm: (appName: Ptr); {pointer to application name in buffer} END; æC æKY ATPParamBlock ATPPBPtr æFp AppleTalk.p æT RECORD æD ATPPBPtr = ^ATPParamBlock; ATPParamBlock = PACKED RECORD qLink: QElemPtr; {next queue entry} qType: INTEGER; {queue type} ioTrap: INTEGER; {routine trap} ioCmdAddr: Ptr; {routine address} ioCompletion: ProcPtr; {completion routine} ioResult: OSErr; {result code} userData: LONGINT; {ATP user bytes} reqTID: INTEGER; {request transaction ID} ioRefNum: INTEGER; {driver reference number} csCode: INTEGER; {Call command code automatically set} atpSocket: Byte; {currBitMap or socket number} CASE MPPParmType OF SendRequestParm,SendResponseParm, GetRequestParm, AddResponseParm, KillSendReqParm: atpFlags: Byte; {control information} addrBlock: AddrBlock; {source/dest. socket address} reqLength: INTEGER; {request/response length} reqPointer: Ptr; {-> request/response data} bdsPointer: Ptr; {-> response BDS} CASE MPPParmType OF SendRequestParm: (numOfBuffs: Byte; {number of responses expected} timeOutVal: Byte; {timeout interval} numOfResps: Byte; {number of responses actually received} retryCount: Byte; {number of retries} intBuff: INTEGER); {used internally for NSendRequest} SendResponseParm: (filler0: Byte; {numOfBuffs} bdsSize: Byte; {number of BDS elements} transID: INTEGER); {transaction ID} GetRequestParm: (bitMap: Byte; {bit map} filler1: Byte); AddResponseParm: (rspNum: Byte; {sequence number} filler2: Byte); KillSendReqParm: (aKillQEl: Ptr); {ptr to Q element to cancel} END; æC æKY XPPPrmBlkType æFp AppleTalk.p æT RECORD æD XPPPrmBlkType = (XPPPrmBlk,ASPSizeBlk,ASPAbortPrm,xCallParam); æC æKY XPPSubPrmType æFp AppleTalk.p æT RECORD æD XPPSubPrmType = (ASPOpenPrm,ASPSubPrm); æC æKY XPPEndPrmType æFp AppleTalk.p æT RECORD æD XPPEndPrmType = (AFPLoginPrm,ASPEndPrm); æC æKY XPPParamBlock XPPParmBlkPtr æFp AppleTalk.p æT RECORD æD XPPParmBlkPtr = ^XPPParamBlock; XPPParamBlock = PACKED RECORD qLink: QElemPtr; qType: INTEGER; {queue type} ioTrap: INTEGER; {routine trap} ioCmdAddr: Ptr; {routine address} ioCompletion: ProcPtr; {completion routine} ioResult: OSErr; {result code} cmdResult: LONGINT; {command result (ATP user bytes)} ioVRefNum: INTEGER; {volume reference or drive number} ioRefNum: INTEGER; {driver reference number} csCode: INTEGER; {call command code} CASE XPPPrmBlkType OF ASPAbortPrm: (abortSCBPtr: Ptr); {SCB pointer for AbortOS} ASPSizeBlk: (aspMaxCmdSize: INTEGER; {for SPGetParms} aspQuantumSize: INTEGER; {for SPGetParms} numSesss: INTEGER); {for SPGetParms} XPPPrmBlk: (sessRefnum: INTEGER; {offset to session refnum} aspTimeout: Byte; {timeout for ATP} aspRetry: Byte; {retry count for ATP} CASE XPPSubPrmType OF ASPOpenPrm: (serverAddr: AddrBlock; {server address block} scbPointer: Ptr; {SCB pointer} attnRoutine: Ptr); {attention routine pointer} ASPSubPrm: (cbSize: INTEGER; {command block size} cbPtr: Ptr; {command block pointer} rbSize: INTEGER; {reply buffer size} rbPtr: Ptr; {reply buffer pointer} CASE XPPEndPrmType OF AFPLoginPrm: (afpAddrBlock: AddrBlock; {address block in AFP login} afpSCBPtr: Ptr; {SCB pointer in AFP login} afpAttnRoutine: Ptr); {Attn routine pointer in AFP login} ASPEndPrm: (wdSize: INTEGER; {write data size} wdPtr: Ptr; {write data pointer} ccbStart: ARRAY [0..295] OF Byte))); {afpWrite max size = 296, else 150} xCallParam: (xppSubCode: Integer; {always zipGetZoneList (6)} xppTimeout: Byte; {retry interval (seconds)} xppRetry: Byte; {retry count} filler1: Integer; {word space for rent. see the super.} zipBuffPtr: Ptr; {pointer to buffer (must be 578 bytes)} zipNumZones: Integer; {no. of zone names in this response} zipLastFlag: Byte; {non-zero if no more zones} filler2: Byte; {filler} ziplnfoField: PACKED ARRAY [1..70] OF Byte; {on initial call, set first word to zero} END; æC æKY OpenXPP æFp AppleTalk.p æT FUNCTION æD FUNCTION OpenXPP(VAR xppRefnum: INTEGER): OSErr; æDT myVariable := OpenXPP(xppRefnum); æRI æRI æC »Opening the .XPP Driver To open the .XPP driver, issue a Device Manager Open call. (Refer to the Device Manager chapter.) The name of the .XPP driver is '.XPP'. The original Macintosh ROMs require that .XPP be opened only once. With new ROMs, the .XPP unit number can always be obtained through an Open call. With old ROMs only, the .XPP unit number must be hard coded to XPPUnitNum (40) since only one Open call can be issued to the driver. The .XPP driver cannot be opened unless AppleTalk is open. The application must ensure that the .MPP and .ATP drivers are opened, as described earlier in this chapter. The xppLoaded bit (bit 5) in the PortBUse byte in low memory indicates whether or not the .XPP driver is open. »Example The following is an example of the procedure an application might use to open the .XPP driver. ; Routine: OpenXPP ; ; Open the .XPP driver and return the driver refNum for it. ; ; Exit: D0 = error code (ccr's set) ; D1 = XPP driver refNum (if no errors) ; ; All other registers preserved ; xppUnitNum EQU 40 ;default XPP driver number xppTfRNum EQU -(xppUnitNum+1) ;default XPP driver refNum OpenXPP MOVE.L A0-A1/D2,-(SP) ;save registers MOVE ROM85,D0 ;check ROM type byte BPL.S @10 ;branch if >=128K ROMs BTST #xppLoadedBit,PortBUse ;is the XPP driver open already? BEQ.S @10 ;if not open, then branch to Open code MOVE #xppTfRNum,D1 ;else use this as driver refnum MOVEQ #0,D0 ;set noErr BRA.S @90 ;and exit ; ; XPP driver not open. Make an _Open call to it. If using a 128K ; ROM machine and the driver is already open, we will make another ; Open call to it just so we get the correct driver refNum. ; @10 SUB #ioQElSize,SP ;allocate temporary param block MOVE.L SP,A0 ;A0 -> param block LEA XPPName, A1 ;A1 -> XPP (ASP/AFP) driver name MOVE.L A1,ioFileName(A0) ;driver name into param block CLR.B ioPermssn(A0) ;clear permissions byte _Open MOVE ioRefNum(A0),D1 ;D1=driver refNum (invalid if error) ADD #ioQElSize,SP ;deallocate temp param block @90 MOVE.L (SP)+,A0-A1/D2 ;restore registers TST D0 ;error? (set ccr's) RTS XPPName DC.B 4 ;length of string DC.B '.XPP' ;driver name From Pascal, XPP can be opened through the OpenXPP call, which returns the driver’s reference number: FUNCTION OpenXPP (VAR xppRefnum: INTEGER) : OSErr; »Open Errors Errors returned when calling the Device Manager Open routine if the function does not execute properly include the following: • errors returned by System • portInUse is returned if the AppleTalk port is in use by a driver other than AppleTalk or if AppleTalk is not open. »Closing the .XPP Driver To close the .XPP driver, call the Device Manager Close routine. Warning: There is generally no reason to close the driver. Use this call sparingly, if at all. This call should generally be used only by system-level applications. »Close Errors Errors returned when calling the Device Manager Close routine if the function does not execute properly include the following: • errors returned by System • closeErr (new ROMs only) is returned if you try to close the driver and there are sessions active through that driver. When sessions are active, closeErr is returned and the driver remains open. • on old ROMs the driver is closed whether or not sessions are active and no error is returned. Results are unpredictable if sessions are still active. »Session Control Block The session control block (SCB) is a nonrelocatable block of data passed by the caller to XPP upon session opening. XPP reserves this block for use in maintaining an open session. The SCB size is defined by the constant scbMemSize. The SCB is a locked block, and as long as the session is open, the SCB cannot be modified in any way by the application. There is one SCB for each open session. This block can be reused once a CloseSess call is issued and completed for that session or when the session is indicated as closed. æKY ASPOpenSession æFp AppleTalk.p æT FUNCTION æD FUNCTION ASPOpenSession(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := ASPOpenSession(thePBptr,async); æRI V-536 æC »AppleTalk Session Protocol Functions This section contains descriptions of the .XPP driver functions that you can call. Each function description shows the required parameter block fields, their offsets within the parameter block and a brief definition of the field. Possible result codes are also described. »Note on Result Codes An important distinction exists between the aspParamErr and aspSessClose result codes that may be returned by the .XPP driver. When the driver returns aspParamErr to a call that takes as an input a session reference number, the session reference number does not relate to a valid open session. There could be several reasons for this, such as the workstation or server end closed the session or the server end of the session died. The aspSessClosed result code indicates that even though the session reference number relates to a valid session, that particular session is in the process of closing down (although the session is not yet closed). FUNCTION ASPOpenSession (xParamBlock: XPPParmBlkPtr; async: BOOLEAN) : OSErr; Parameter block --> 26 csCode word Always ASPOpenSess --> 28 sessRefnum word Session reference number --> 30 aspTimeout byte Retry interval in seconds --> 31 aspRetry byte Number of retries --> 32 serverAddr long word Server socket address --> 36 scbPointer pointer Pointer to session control block --> 40 attnRoutine pointer Pointer to attention routine ASPOpenSession initiates (opens) a session between the workstation and a server. The required parameter block is shown above. A brief definition of the fields follows. SessRefnum is a unique number identifying the open session between the workstation and the server. The SessRefnum is returned when the function completes successfully and is used in all calls to identify the session. ASPTimeOut is the interval in seconds between retries of the open session request. ASPRetry is the number of retries that will be attempted. ServerAddr is the network identifier or address of the socket on which the server is listening. SCBPointer points to a nonrelocatable block of data for the session control block (SCB) that the .XPP driver reserves for use in maintaining an open session. The SCB size is defined by the constant scbMemSize. The SCB is a locked block and as long as the session is open, the SCB cannot be modified in any way by the application. There is one SCB for each open session. This block can be reused when a CloseSess call is issued and completed for that session, or when the session is indicated as closed through return of aspParamErr as the result of a call for that session. AttnRoutine is a pointer to a routine that is invoked if an attention from the server is received, or upon session closing. If this pointer is equal to zero, no attention routine will be invoked. Result codes aspNoMoreSess Driver cannot support another session aspParamErr Server returned bad (positive) error code aspNoServers No servers at that address, or the server did not respond to the request reqAborted OpenSess was aborted by an AbortOS aspBadVersNum Server cannot support the offered version number aspServerBusy Server cannot open another session Note: The number of sessions that the driver is capable of supporting depends on the machine that the driver is running on. æKY ASPCloseSession æFp AppleTalk.p æT FUNCTION æD FUNCTION ASPCloseSession(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := ASPCloseSession(thePBptr,async); æRI V-537 æC Parameter block --> 26 csCode word Always ASPCloseSession --> 28 sessRefnum word Session reference number ASPCloseSession closes the session identified by the sessRefnum returned in the ASPOpenSession call. ASPCloseSession aborts any calls that are active on the session, closes the session, and calls the attention routine, if any, with an attention code of zero (zero is invalid as a real attention code). Result codes aspParamErr Parameter error, indicates an invalid session reference number aspSessClosed Session already in process of closing æKY ASPAbortOS æFp AppleTalk.p æT FUNCTION æD FUNCTION ASPAbortOS(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := ASPAbortOS(thePBptr,async); æRI V-537 æC Parameter block --> 26 csCode word Always ASPAbortOS --> 28 abortSCBPointer pointer Pointer to session control block ASPAbortOS aborts a pending (not yet completed) ASPOpenSession call. The aborted ASPOpenSession call will return a reqAborted error. AbortSCBPointer points to the original SCB used in the the pending ASPOpenSession call. Result codes cbNotFound SCB not found, no outstanding open session to be aborted. Pointer did not point to an open session SCB. æKY ASPGetParms æFp AppleTalk.p æT FUNCTION æD FUNCTION ASPGetParms(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := ASPGetParms(thePBptr,async); æRI V-538 æC Parameter block --> 26 csCode word Always ASPGetParms --> 28 aspMaxCmdSize word Maximum size of command block --> 30 aspQuantumSize word Maximum data size --> 32 numSesss word Number of sessions ASPGetParms returns three ASP parameters. This call does not require an open session. ASPMaxCmdSize is the maximum size of a command that can be sent to the server. ASPQuantumSize is the maximum size of data that can be transferred to the server in a Write request or from the server in a command reply. NumSess is the number of concurrent sessions supported by the driver. æKY ASPCloseAll æFp AppleTalk.p æT FUNCTION æD FUNCTION ASPCloseAll(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := ASPCloseAll(thePBptr,async); æRI V-538 æC Parameter block --> 26 csCode word Always ASPCloseAll ASPCloseAll closes every session that the driver has active, aborting all active requests and invoking the attention routines where provided. This call should be used carefully. ASPCloseAll can be used as a system level resource for making sure all sessions are closed prior to closing the driver. æKY ASPUserWrite æFp AppleTalk.p æT FUNCTION æD FUNCTION ASPUserWrite(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := ASPUserWrite(thePBptr,async); æRI V-538 æC Parameter block --> 18 cmdResult long word ASP command result --> 26 csCode word Always UserWrite --> 28 sessRefnum word Session reference number --> 30 aspTimeout byte Retry interval in seconds --> 32 cbSize word Command block size --> 34 cbPtr pointer Command block pointer <-> 38 rbSize word Reply buffer size and reply size --> 40 rbPtr pointer Reply buffer pointer <-> 44 wdSize word Write data size --> 46 wdPtr pointer Write data pointer --> 50 ccbStart record Start of memory for CCB ASPUserWrite transfers data on a session. ASPUserWrite is one of the two main calls that can be used to transfer data on an ASP session. The other call that performs a similar data transfer is ASPUserCommand described below. The ASPUserWrite command returns data in two different places. Four bytes of data are returned in the cmdResult field and a variable size reply buffer is also returned. CmdResult is four bytes of data returned by the server. SessRefnum is the session reference number returned in the ASPOpenSession call. ASPTimeOut is the interval in seconds between retries of the call. Notice that there is no aspRetry field (retries are infinite). The command will be retried at the prescribed interval until completion or the session is closed. CBSize is the size in bytes of the command data that is to be written on the session. The size of the command block must not exceed the value of aspMaxCmdSize returned by the ASPGetParms call. Note that this buffer is not the data to be written by the command but only the data of the command itself. CBPtr points to the command data. RBSize is passed and indicates the size of the reply buffer in bytes expected by the command. RBSize is also returned and indicates the size of the reply that was actually returned. RBPtr points to the reply buffer. WDSize is passed and indicates the size of the write data in bytes to be sent by the command. WDSize is also returned and indicates the size of the write data that was actually written. WDPointer points to the write data buffer. CCBStart is the start of the memory to be used by the .XPP driver for the command control block. The size of this block is equal to a maximum of 296 bytes. To determine the exact requirement, refer to the CCB Sizes section of this document. Result codes aspParamErr Invalid session number, session has been closed aspSizeErr Command block size is bigger than MaxCmdSize aspSessClosed Session is closing aspBufTooSmall Reply is bigger than response buffer; the buffer will be filled, data will be truncated æKY ASPUserCommand æFp AppleTalk.p æT FUNCTION æD FUNCTION ASPUserCommand(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := ASPUserCommand(thePBptr,async); æRI V-539 æC Parameter block --> 18 cmdResult long word ASP command result --> 26 csCode word Always ASPUserCommand --> 28 sessRefnum word Session number --> 30 aspTimeout byte Retry interval in seconds --> 32 cbSize word Command block size --> 34 cbPtr pointer Command block pointer <-> 38 rbSize word Reply buffer and reply size --> 40 rbPtr pointer Reply buffer pointer --> 50 ccbStart record Start of memory for CCB ASPUserCommand is used to send a command to the server on a session. SessRefnum is the session reference number returned in the ASPOpenSession call. ASPTimeOut is the interval in seconds between retries of the call. Notice that there is no aspRetry field (retries are infinite). The command will be retried at the prescribed interval until completion or the session is closed. CBSize is the size in bytes of the block of data that contains the command to be sent to the server on the session. The size of the command block must not exceed the value of aspMaxCmdSize returned by the ASPGetParms call. CBPointer points to the block of data containing the command that is to be sent to the server on the session. RBSize is passed and indicates the size of the reply buffer in bytes expected by the command. RBSize is also returned and indicates the size of the reply that was actually returned. RBPtr points to the reply buffer. CCBStart is the start of the memory to be used by the .XPP driver for the command control block. The size of this block is equal to a maximum of 150 bytes. To determine the exact requirement refer to the CCB Sizes section of this document. Result codes aspParamErr Invalid session number, session has been closed aspSizeErr Command block size is bigger than MaxCmdSize aspSessClosed Session is closing aspBufTooSmall Reply is bigger than response buffer; the buffer will be filled, data will be truncated æKY ASPGetStatus æFp AppleTalk.p æT FUNCTION æD FUNCTION ASPGetStatus(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := ASPGetStatus(thePBptr,async); æRI V-540 æC Parameter block --> 26 csCode word Always ASPGetStatus --> 30 aspTimeout byte Retry interval in seconds --> 31 aspRetry byte Number of retries --> 32 serverAddr long word Server socket address <-> 38 rbSize word Reply buffer and reply size --> 40 rbPtr pointer Reply buffer pointer --> 50 ccbStart record Start of memory for CCB ASPGetStatus returns server status. This call is also used as GetServerInfo at the AFP level. This call is unique in that it transfers data over the network without having a session open. This call does not pass any data but requests that server status be returned. ASPTimeOut is the interval in seconds between retries of the call. ASPRetry is the number of retries that will be attempted. ServerAddr is the network identifier or address of the socket on which the server is listening. RBSize is passed and indicates the size of the reply buffer in bytes expected by the command. RBSize is also returned and indicates the size of the reply that was actually returned. RBPtr points to the reply buffer. CCBStart is the start of the memory to be used by the .XPP driver for the command control block. The size of this block is equal to a maximum of 150 bytes. To determine the exact requirement refer to the CCB Sizes section of this document. Result codes aspBufTooSmall Reply is bigger than response buffer, or Replysize is bigger than ReplyBuffsize aspNoServer No response from server at address used in call æKY AFPCommand æFp AppleTalk.p æT FUNCTION æD FUNCTION AFPCommand(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := AFPCommand(thePBptr,async); æRI V-542 æC »AFPCall Function The AFPCall function can have one of the following command formats. • General • Login • AFPWrite • AFPRead »General Command Format FUNCTION AFPCommand (xParamBlock: XPPParmBlkPtr; async: BOOLEAN) : OSErr; Parameter block --> 18 cmdResult long word AFP command result --> 26 csCode word Always AFPCall --> 28 sessRefnum word Session reference number --> 30 aspTimeout byte Retry interval in seconds --> 32 cbSize word Command buffer size --> 34 cbPtr pointer Command buffer <-> 38 rbSize word Reply buffer size and reply size --> 40 rbPtr pointer Reply buffer pointer <-> 44 wdSize word Write data size --> 46 wdPtr pointer Write data pointer --> 50 ccbStart record Start of memory for CCB The general command format for the AFPCall function passes an AFP command to the server. This format is used for all AFP calls except AFPLogin, AFPRead, and AFPWrite. Note that from Pascal this call is referred to as AFPCommand. CmdResult is four bytes of data returned from the server containing an indication of the result of the AFP command. SessRefnum is the session reference number returned in the AFPLogin call. ASPTimeOut is the interval in seconds between retries of the call by the driver. CBSize is the size in bytes of the block of data that contains the command to be sent to the server on the session. The size of the command block must not exceed the value of aspMaxCmdSize returned by the ASPGetParms call. CBPtr points to start of the block of data (command block) containing the command that is to be sent to the server on the session. The first byte of the command block must contain the AFP command byte. Subsequent bytes in the command buffer contain the parameters associated with the command as defined in the AFP document. RBSize is passed and indicates the size of the reply buffer in bytes expected by the command. RBSize is also returned and indicates the size of the reply that was actually returned. RBPtr points to the reply buffer. WDSize is the size of data to be written to the server (only used if the command is one that is mapped to an ASPUserWrite). WDPtr points to the write data buffer (only used if the command is one that is mapped to an ASPUserWrite). CCBStart is the start of the memory to be used by the .XPP driver for the command control block. The size of this block is equal to a maximum of 296 bytes. To determine the exact requirement refer to the CCB Sizes section of this document. Result codes aspParamErr Invalid session number; session has been closed aspSizeErr Command block size is bigger than MaxCmdSize aspSessClosed Session is closing aspBufTooSmall Reply is bigger than response buffer or buffer will be filled, data will be truncated afpParmError AFP command block size is equal to zero. This error will also be returned if the command byte in the command block is equal to 0 or $FF (255) or GetSrvrStatus (15). »Login Command Format The AFP login command executes a series of AFP operations as defined in the AFP Draft Proposal. For further information, refer to the AFP document. FUNCTION AFPCommand (xParamBlock: XPPParmBlkPtr; async: BOOLEAN): OSErr; Parameter block --> 18 cmdResult long word AFP command result --> 26 csCode word Always AFPCall --> 28 sessRefnum word Session reference number --> 30 aspTimeout byte Retry interval in seconds --> 31 aspRetry byte Number of retries --> 32 cbSize word Command buffer size --> 34 cbPtr pointer Command buffer <-> 38 rbSize word Reply buffer size and reply size --> 40 rbPtr pointer Reply buffer pointer --> 44 afpAddrBlock long word Server address block <-> 48 afpSCBPtr pointer SCB pointer <-> 52 afpAttnRoutine pointer Attention routine pointer --> 50 ccbStart record Start of command control block CmdResult is four bytes of data returned from the server containing an indication of the result of the AFP command. SessRefnum is the session reference number (returned by the AFPLogin call). ASPTimeOut is the interval in seconds between retries of the call. ASPRetry is the number of retries that will be attempted. CBSize is the size in bytes of the block data that contains the command to be sent to the server on the session. The size of the command block must not exceed the value of aspMaxCmdSize returned by the ASPGetParms call. CBPtr points to the block of data (command block) containing the AFP login command that is to be sent to the server on the session. The first byte of the command block must be the AFP login command byte. Subsequent bytes in the command buffer contain the parameters associated with the command. RBSize is passed and indicates the size of the reply buffer in bytes expected by the command. RBSize is also returned and indicates the size of the reply that was actually returned. RBPtr points to the reply buffer. AFPServerAddr is the network identifier or address of the socket on which the server is listening. AFPSCBPointer points to a locked block of data for the session control block (SCB). The SCB size is defined by scbMemSize. The SCB is a locked block, and as long as the session is open, the SCB cannot be modified in any way by the application. There is one SCB for each open session. AFPAttnRoutine is a pointer to a routine that is invoked if an attention from the server is received. When afpAttnRoutine is equal to zero, no attention routine will be invoked. CCBStart is the start of the memory to be used by the .XPP driver for the command control block. The size of this block is equal to a maximum of 150 bytes. To determine the exact requirement refer to the CCB Sizes section later in this chapter. Note: In the parameter block, the afpSCBPointer and the afpAttnRoutine fields overlap with the start of the CCB and are modified by the call. Result codes aspSizeErr Command block size is bigger than MaxCmdSize aspBufTooSmall Reply is bigger than response buffer or buffer will be filled, data will be truncated aspNoServer Server not responding aspServerBusy Server cannot open another session aspBadVersNum Server cannot support the offered ASP version number aspNoMoreSess Driver cannot support another session. »AFPWrite Command Format The AFPWrite and AFPRead command formats allow the calling application to make AFP-level calls that read or write a data block that is larger than a single ASP-level call is capable of reading or writing. The maximum number of bytes of data that can be read or written at the ASP level is equal to quantumSize. FUNCTION AFPCommand (xParamBlock: XPPParmBlkPtr; async: BOOLEAN) : OSErr; Parameter block --> 18 cmdResult long word AFP command result --> 26 csCode word Always AFPCall --> 28 sessRefnum word Session number --> 30 aspTimeout byte Retry interval in seconds --> 32 cbSize word Command buffer size --> 34 cbPtr pointer Command buffer <-> 38 rbSize word Reply buffer size and reply size --> 40 rbPtr pointer Reply buffer pointer --> 44 wdSize word (used internally) <-> 46 wdPtr pointer Write data pointer (updated) --> 50 ccbStart record Start of memory for CCB CmdResult is four bytes of data returned from the server containing an indication of the result of the AFP command. SessRefnum is the session reference number returned in the AFPLogin call. ASPTimeOut is the interval in seconds between retries of the call. CBSize is the size in bytes of the block data that contains the command to be sent to the server on the session. The size of the command block must not exceed the value of aspMaxCmdSize returned by the aspGetParms call. CBPtr points to the block of data (see command block structure below) containing the AFP write command that is to be sent to the server on the session. The first byte of the Command Block must contain the AFP write command byte. RBSize is passed and indicates the size of the reply buffer in bytes expected by the command. RBSize is also returned and indicates the size of the reply that was actually returned. RBPtr points to the reply buffer. WDSize is used internally. Note: This command does not pass the write data size in the queue element but in the command buffer. XPP will look for the size in that buffer. WDPtr is a pointer to the block of data to be written. Note that this field will be updated by XPP as it proceeds and will always point to that section of the data which XPP is currently writing. CCBStart is the start of the memory to be used by the XPP driver for the command control block. The size of this block is equal to a maximum of 296 bytes. To determine the exact requirement refer to the CCB Sizes section later in this chapter. Command Block Structure: The AFP write command passes several arguments to XPP in the command buffer itself. The byte offsets are relative to the location pointed to by cbPtr. --> 0 cmdByte byte AFP call command byte --> 1 startEndFlag byte Start/end Flag <-> 4 rwOffset long word Offset within fork to write <-> 8 reqCount long word Requested count CmdByte is the AFP call command byte and must contain the AFP write command code. StartEndFlag is a one-bit flag (the high bit of the byte) indicating whether the rwOffset field is relative to the beginning or the end of the fork (all other bits are zero). 0 = relative to the beginning of the fork 1 = relative to the end of the fork RWOffset is the byte offset within the fork at which the write is to begin. ReqCount indicates the size of the data to be written and is returned as the actual size written. The rwOffset and reqCount fields are modified by XPP as the write proceeds and will always indicate the current value of these fields. The Pascal structure of the AFP command buffer follows: AFPCommandBlock = PACKED RECORD cmdByte: Byte; startEndFlag: Byte; forkRefNum: INTEGER; {used by server} rwOffset: LONGINT; reqCount: LONGINT; newLineFlag: Byte; {unused by write} newLineChar: CHAR; {unused by write} END; Result codes aspParamErr Invalid session number aspSizeErr Command block size is bigger than MaxCmdSize aspSessClosed Session is closing aspBufTooSmall Reply is bigger than response buffer »AFPRead Command Format The AFPWrite and AFPRead command formats allow the calling application to make AFP-level calls that read or write a data block that is larger than a single ASP-level call is capable of reading or writing. The maximum number of bytes of data that can be read or written at the ASP level is equal to quantumSize. FUNCTION AFPCommand (xParamBlock: XPPParmBlkPtr; async: BOOLEAN) : OSErr; Parameter block --> 18 cmdResult long word ASP command result --> 26 csCode word Always AFPCall --> 28 sessRefnum word Session number --> 30 aspTimeout byte Retry interval in seconds --> 32 cbSize word Command buffer size --> 34 cbPtr pointer Command buffer --> 38 rbSize word Used internally <-> 40 rbPtr pointer Reply buffer pointer (updated) --> 50 ccbStart record Start of memory for CCB CmdResult is four bytes of data returned from the server containing an indication of the result of the AFP command. SessRefnum is the session reference number returned in the AFPLogin call. ASPTimeOut is the interval in seconds between retries of the call. CBSize is the size in bytes of the block data that contains the command to be sent to the server on the session. The size of the command block must not exceed the value of aspMaxCmdSize returned by the GetParms call. CBPtr points to the block of data (command block) containing the AFP read command that is to be sent to the server on the session. The first byte of the command block must contain the AFP read command byte. The command block structure is shown below. RBSize is used internally. Note: This command does not pass the read size in the queue element but in the command buffer. XPP will look for the size in that buffer. RBPtr points to the reply buffer. Note that this field will be updated by XPP as it proceeds and will always point to that section of the buffer that XPP is currently reading into. CCBStart is the start of the memory to be used by the .XPP driver for the command control block. The size of this block is equal to a maximum of 150 bytes. To determine the exact requirement refer to The CCB Sizes section later in this chapter. Command Block Structure: The AFP read command passes several arguments to XPP in the command buffer itself. The byte offsets are relative to the location pointed to by cbPointer. --> 0 cmdByte byte AFP call command byte <-> 4 rwOffset long word Offset within fork to read <-> 8 reqCount long word Requested count --> 12 newLineFlag byte Newline Flag --> 13 newLineChar byte Newline Character CmdByte is the AFP call command byte and must contain the AFP read command code. RWOffset is the byte offset within the fork at which the read is to begin. ReqCount indicates the size of the read data buffer and is returned as the actual size read. The rwOffset and reqCount fields are modified by XPP as the read proceeds and will always indicate the current value of these fields. NewLineFlag is a one-bit flag (the high bit of the byte) indicating whether or not the read is to terminate at a specified character (all other bits are zero). 0 = no Newline Character is specified 1 = a Newline Character is specified NewLineChar is any character from $00 to $FF (inclusive) that, when encountered in reading the fork, causes the read operation to terminate. The Pascal structure of the AFPCommand follows: AFPCommandBlock = PACKED RECORD cmdByte: Byte; startEndFlag: Byte; {unused for read} forkRefNum: INTEGER; {used by server} rwOffset: LONGINT; reqCount: LONGINT; newLineFlag: Byte; newLineChar: CHAR; END; Result codes aspParamErr Invalid session number aspSizeErr Command block size is bigger than MaxCmdSize aspSessClosed Session is closing aspBufTooSmall Reply is bigger than response buffer æKY GetLocalZones æFp AppleTalk.p æT FUNCTION æD FUNCTION GetLocalZones(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := GetLocalZones(thePBptr,async); æRI VI æC Parameter block ¨ 16 ioResult word result code Æ 26 csCode word routine selector; always xCall Æ 28 xppSubCode word routine selector; getLocalZones Æ 30 xppTimeOut byte retry interval in seconds Æ 31 xppRetry byte retry count Æ 34 zipBuffPtr pointer pointer to data buffer ¨ 38 zipNumZones word number of names returned ¨ 40 zipLastFlag byte nonzero if no more names Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0 The GetLocalZones function returns a list of all the zone names on the local network; that is, the network that includes the node on which your application is running. The ioResult parameter returns the result of the function; if you call the function asynchronously, the function sets this field to 1 as soon as it begins execution, and changes the field to the actual result code when it completes execution. The csCode and xppSubCode parameters are routine selectors and are automatically set by the MPW interface to xCall and getLocalZones for this function. The xppTimeOut field specifies the amount of time, in seconds, that the .ATP driver should wait between attempts to obtain the data. A value of 3 or 4 for the xppTimeOut field generally gives good results. The xppRetry field specifies the number of times the .ATP driver should attempt to obtain the data before returning the ReqFailed (request failed) result code. A value of 3 or 4 for the xppRetry field usually works well. The zipBuffPtr is a pointer to a 578-byte data buffer that you must allocate. The Zone Information Protocol returns the zone names into this buffer as a packed array of packed Pascal strings. The zipNumZones parameter returns the number of zone names that ZIP placed in the data buffer. The .XPP driver sets the zipLastFlag field to 1 if there are no more zone names for your network. If the zipLastFlag field is still 0 when the GetLocalZones function has completed execution, you must empty the data buffer pointed to by the zipBuffPtr parameter and immediately call the GetLocalZones function again without changing the value in the zipInfoField parameter. The zipInfofield parameter is a 70-byte data buffer that you must allocate for use by ZIP. You must set the first word of this buffer to 0 before you call the GetLocalZones function the first time, and not change the contents of this field thereafter. æKY GetZoneList æFp AppleTalk.p æT FUNCTION æD FUNCTION GetZoneList(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := GetZoneList(thePBptr,async); æRI VI æC Parameter block ¨ 16 ioResult word result code Æ 26 csCode word routine selector; always xCall Æ 28 xppSubCode word routine selector; getZoneList Æ 30 xppTimeOut byte retry interval in seconds Æ 31 xppRetry byte retry count Æ 34 zipBuffPtr pointer pointer to data buffer ¨ 38 zipNumZones word number of names returned ¨ 40 zipLastFlag byte nonzero if no more names Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0 The GetZoneList function returns a complete list of all the zone names on the internet. Use the GetLocalZones function to obtain a list of only the zone names on the local network. The ioResult parameter returns the result of the function; if you call the function asynchronously, the function sets this field to 1 as soon as it begins execution, and changes the field to the actual result code when it completes execution. The csCode and xppSubCode parameters are routine selectors and are automatically set by the MPW interface to xCall and getZoneList for this function. The xppTimeOut field specifies the amount of time, in seconds, that the .ATP driver should wait between attempts to obtain the data. A value of 3 or 4 for the xppTimeOut field generally gives good results. The xppRetry field specifies the number of times the .ATP driver should attempt to obtain the data before returning the ReqFailed (request failed) result code. A value of 3 or 4 for the xppRetry field usually works well. The zipBuffPtr is a pointer to a 578-byte data buffer that you must allocate. The Zone Information Protocol returns the zone names into this buffer as Pascal strings. The zipNumZones parameter returns the number of zone names that ZIP placed in the data buffer. The .XPP driver sets the zipLastFlag field to 1 if there are no more zone names for the internet. If the zipLastFlag field is still 0 when the GetZoneList function has completed execution, you must empty the data buffer pointed to by the zipBuffPtr parameter and immediately call the GetZoneList function again without changing the value in the zipInfoField parameter. The zipInfofield parameter is a 70-byte data buffer that you must allocate for use by ZIP. You must set the first word of this buffer to 0 before you call the GetZoneList function the first time, and not change the contents of this field thereafter. æKY GetMyZone æFp AppleTalk.p æT FUNCTION æD FUNCTION GetMyZone(thePBptr: XPPParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := GetMyZone(thePBptr,async); æRI VI æC The .XPP driver provides three functions that obtain information about zones. All three functions use the Zone Information Protocol to return the names of zones: The GetMyZone function returns the AppleTalk zone name of the node on which your application is running; the GetLocalZones function returns a list of zone names on the network that includes the node on which your application is running; and the GetZoneList function returns a complete list of zones on the internet. Assembly-language note: The .XPP driver functions all use the same value (xCall, which is equal to 246) for the csCode parameter to the xCallParam parameter block. The xCall routine uses the value of the xppSubCode parameter to distinguish between the functions, as follows: Function xppSubCode Value GetMyZone getMyZone 7 GetLocalZones getLocalZones 5 GetZoneList getZoneList 6 FUNCTION GetMyZone (thePBptr:XCallParamPtr; async: BOOLEAN) : OSErr; Parameter block ¨ 16 ioResult word result code Æ 26 csCode word routine selector; always xCall Æ 28 xppSubCode word routine selector; getMyZone Æ 30 xppTimeOut byte retry interval in seconds Æ 31 xppRetry byte retry count Æ 34 zipBuffPtr long pointer to data buffer Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0 The GetMyZone function returns only the zone name of the node on which your application is running. The ioResult parameter returns the result of the function; if you call the function asynchronously, the function sets this field to 1 as soon as it begins execution, and changes the field to the actual result code when it completes execution. The csCode and xppSubCode parameters are routine selectors and are automatically set by the MPW interface to xCall and getMyZone for this function. The xppTimeOut field specifies the amount of time, in seconds, that the .ATP driver should wait between attempts to obtain the data. A value of 3 or 4 for the xppTimeOut field generally gives good results. The xppRetry field specifies the number of times the .ATP driver should attempt to obtain the data before returning the ReqFailed (request failed) result code. A value of 3 or 4 for the xppRetry field usually works well. The zipBuffPtr is a pointer to a 33-byte data buffer that you must allocate. The Zone Information Protocol returns the zone name into this buffer as a Pascal string. The zipInfo field is a 70-byte data buffer that you must allocate for use by ZIP. You must set the first word of this buffer to 0 before you call the GetMyZone function. Result codes noErr 0 no error noBridgeErr –93 no router is available reqFailed –1096 Request to contact router failed; retry count exceeded æKY PAttachPH æFp AppleTalk.p æT FUNCTION æD FUNCTION PAttachPH(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PAttachPH(thePBptr,async); æRI II-308, V-513 æC AttachPH function Parameter block -> 26 csCode word ;always attachPH -> 28 protType byte ;ALAP protocol type -> 30 handler pointer ;protocol handler AttachPH adds the protocol handler pointed to by handler to the node's protocol table. ProtType specifies what kind of frame the protocol handler can service. After AttachPH is called, the protocol handler is called for each incoming frame whose ALAP protocol type equals protType. Result codes noErr No error lapProtErr Error attaching protocol type æKY PDetachPH æFp AppleTalk.p æT FUNCTION æD FUNCTION PDetachPH(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PDetachPH(thePBptr,async); æRI II-308, V-513 æC DetachPH function Parameter block -> 26 csCode word ;always detachPH -> 28 protType byte ;ALAP protocol type DetachPH removes from the node's protocol table the specified ALAP protocol type and corresponding protocol handler. Result codes noErr No error lapProtErr Error detaching protocol type æKY PWriteLAP æFp AppleTalk.p æT FUNCTION æD FUNCTION PWriteLAP(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PWriteLAP(thePBptr,async); æRI II-307, V-513 æC WriteLAP function Parameter block -> 26 csCode word ;always writeLAP -> 30 wdsPointer pointer ;write data structure WriteLAP sends a frame to another node. The frame data and destination of the frame are described by the write data structure pointed to by wdsPointer. The first two data bytes of an ALAP frame sent to another computer using the AppleTalk Manager must indicate the length of the frame in bytes. The ALAP protocol type byte must be in the range 1 to 127. Result codes noErr No error excessCollsns No CTS received after 32 RTS's ddpLengthErr Packet length exceeds maximum lapProtErr Invalid ALAP protocol type æKY POpenSkt æFp AppleTalk.p æT FUNCTION æD FUNCTION POpenSkt(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := POpenSkt(thePBptr,async); æRI II-311, V-513 æC OpenSkt function Parameter block -> 26 csCode word ;always openSkt <-> 28 socket byte ;socket number -> 30 listener pointer ;socket listener OpenSkt adds a socket and its socket listener to the socket table. If the socket parameter is nonzero, it must be in the range 64 to 127, and it specifies the socket's number; if socket is 0, OpenSkt opens a socket with a socket number in the range 128 to 254, and returns it in the socket parameter. Listener contains a pointer to the socket listener. OpenSkt will return ddpSktErr if you pass the number of an already opened socket, if you pass a socket number greater than 127, or if the socket table is full (the socket table can hold a maximum of 12 sockets). Result codes noErr No error ddpSktErr Socket error æKY PCloseSkt æFp AppleTalk.p æT FUNCTION æD FUNCTION PCloseSkt(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PCloseSkt(thePBptr,async); æRI II-312,V513 æC CloseSkt function Parameter block -> 26 csCode word ;always closeSkt -> 28 socket byte ;socket number CloseSkt removes the entry of the specified socket from the socket table. If you pass a socket number of 0, or if you attempt to close a socket that isn't open, CloseSkt will return ddpSktErr. Result codes noErr No error ddpSktErr Socket error æKY PWriteDDP æFp AppleTalk.p æT FUNCTION æD FUNCTION PWriteDDP(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PWriteDDP(thePBptr,async); æRI II-312,V-513 æC WriteDDP function Parameter block -> 26 csCode word ;always writeDDP -> 28 socket byte ;socket number -> 29 checksumFlag byte ;checksum flag -> 30 wdsPointer pointer ;write data structure WriteDDP sends a datagram to another socket. WDSPointer points to a write data structure containing the datagram and the address of the destination socket. If checksumFlag is TRUE, WriteDDP will compute the checksum for all datagrams requiring long headers. Result codes noErr No error ddpLenErr Datagram length too big ddpSktErr Socket error noBridgeErr No bridge found æKY PRegisterName æFp AppleTalk.p æT FUNCTION æD FUNCTION PRegisterName(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PRegisterName(thePBptr,async); æRI II-322,V-513 æC RegisterName function Parameter block -> 26 csCode word ;always registerName -> 28 interval byte ;retry interval <-> 29 count byte ;retry count -> 30 ntQElPtr pointer ;names table element pointer -> 34 verifyFlag byte ;set if verify needed RegisterName adds the name and address of an entity to the node's names table. NTQElPtr points to a names table entry containing the entity's name and internet address (in the form shown in Figure 13 above). Meta-characters aren't allowed in the object and type fields of the entity name; the zone field, however, must contain the meta-character "*". If verifyFlag is TRUE, RegisterName checks on the network to see if the name is already in use, and returns a result code of nbpDuplicate if so. Interval and count contain the retry interval in eight-tick units and the retry count. When a retry is made, the count field is modified. Warning: The names table entry passed to RegisterName remains the property of NBP until removed from the names table. Don't attempt to remove or modify it. If you've allocated memory using a NewHandle call, you must lock it as long as the name is registered. Warning: VerifyFlag should normally be set before calling RegisterName. Result codes noErr No error nbpDuplicate Duplicate name already exists nbpNISErr Error opening names information socket æKY PLookupName æFp AppleTalk.p æT FUNCTION æD FUNCTION PLookupName(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PLookupName(thePBptr,async); æRI II-323,V-513 æC LookupName function Parameter block -> 26 csCode word ;always lookupName -> 28 interval byte ;retry interval <-> 29 count byte ;retry count -> 30 entityPtr pointer ;pointer to entity name -> 34 retBuffPtr pointer ;pointer to buffer -> 38 retBuffSize word ;buffer size in bytes -> 40 maxToGet word ;matches to get <-> 42 numGotten word ;matches found LookupName returns the addresses of all entities with a specified name. EntityPtr points to the entity's name (in the form shown in Figure 13 above). Meta- characters are allowed in the entity name. RetBuffPtr and retBuffSize contain the location and size of an area of memory in which the tuples describing the entity names and their corresponding addresses should be returned. MaxToGet indicates the maximum number of matching names to find addresses for; the actual number of addresses found is returned in numGotten. Interval and count contain the retry interval and the retry count. LookupName completes when either the number of matches is equal to or greater than maxToGet, or the retry count has been exceeded. The count field is decremented for each retransmission. Note: NumGotten is first set to 0 and then incremented with each match found. You can test the value in this field, and can start examining the received addresses in the buffer while the lookup continues. Result codes noErr No error nbpBuffOvr Buffer overflow æKY PConfirmName æFp AppleTalk.p æT FUNCTION æD FUNCTION PConfirmName(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PConfirmName(thePBptr,async); æRI II-323,V-513 æC ConfirmName function Parameter block -> 26 csCode word ;always confirmName -> 28 interval byte ;retry interval <-> 29 count byte ;retry count -> 30 entityPtr pointer ;pointer to entity name -> 34 confirmAddr pointer ;entity address <- 38 newSocket byte ;socket number ConfirmName confirms that an entity known by name and address still exists (is still entered in the names directory). EntityPtr points to the entity's name (in the form shown in Figure 13 above). ConfirmAddr specifies the address to confirmed. No meta-characters are allowed in the entity name. Interval and count contain the retry interval and the retry count. The socket number of the entity is returned in newSocket. ConfirmName is more efficient than LookupName in terms of network traffic. Result codes noErr No error nbpConfDiff Name confirmed for different socket nbpNoConfirm Name not confirmed æKY PRemoveName æFp AppleTalk.p æT FUNCTION æD FUNCTION PRemoveName(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PRemoveName(thePBptr,async); æRI II-324,V-513 æC RemoveName function Parameter block -> 26 csCode word ;always removeName -> 30 entityPtr pointer ;pointer to entity name RemoveName removes an entity name from the names table of the given entity's node. Result codes noErr No error nbpNotFound Name not found æKY PSetSelfSend æFp AppleTalk.p æT FUNCTION æD FUNCTION PSetSelfSend(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PSetSelfSend(thePBptr,async); æRI V-516 æC _______________________________________________________________________________ »SENDING PACKETS TO ONE’S OWN NODE _______________________________________________________________________________ Upon opening, the ability to send a packet to one’s own node (intranode delivery) is disabled. This feature of the AppleTalk Manager can be manipulated through the SetSelfSend function. Once enabled, it is possible, at all levels, to send packets to entities within one’s own node. An example of where this might be desirable is an application sending data to a print spooler that is actually running in the background on the same node. Enabling (or disabling) this feature affects the entire node and should be performed with care. For instance, a desk accessory may not expect to receive names from within its own node as a response to an NBP look-up; enabling this feature from an application could break the desk accessory. All future programs should be written with this feature in mind. FUNCTION PSetSelfSend (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr; Parameter Block --> 26 csCode word Always PSetSelfSend --> 28 newSelfFlag byte New SelfSend flag <-- 29 oldSelfFlag byte Old SelfSend flag PSetSelfSend enables or disables the intranode delivery feature of the AppleTalk Manager. If newSelfFlag is nonzero, the feature will be enabled; otherwise it will be disabled. The previous value of the flag will be returned in oldSelfFlag. Result Codes noErr No error æKY PKillNBP æFp AppleTalk.p æT FUNCTION æD FUNCTION PKillNBP(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PKillNBP(thePBptr,async); æRI V-518 æC _______________________________________________________________________________ »NAME BINDING PROTOCOL CHANGES _______________________________________________________________________________ Changes to the Name Binding Protocol include supporting multiple concurrent requests and a means for aborting an active request. »Multiple Concurrent NBP Requests NBP now supports multiple concurrent active requests. Specifically, a number of LookupNames, RegisterNames and ConfirmNames can all be active concurrently. The maximum number of concurrent requests is machine dependent; if it is exceeded the error tooManyReqs will be returned. Active requests can be aborted by the PKillNBP call. »KillNBP function FUNCTION PKillNBP (thePBptr: ATPPBPtr; async: BOOLEAN) : OSErr; •••Refer to Technical Note #199:••• Parameter block --> 26 csCode word Always PKillNBP --> 28 aKillQEl pointer Pointer to queue element PKillNBP is used to abort an outstanding LookupName, RegisterName or ConfirmName request. To abort one of these calls, place a pointer to the queue element of the call to abort in a KillQEl and issue the PKillNBP call. The call will be completed with a ReqAborted error. Result Codes noErr No error cbNotFound aKillQEl does not point to a valid NBP queue element æKY PGetAppleTalkInfo æFp AppleTalk.p æT FUNCTION æD FUNCTION PGetAppleTalkInfo(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PGetAppleTalkInfo(thePBptr,async); æRI VI æC You can use the PGetAppleTalkInfo function to obtain information about the .MPP driver. In addition to the node ID and other information pointed to by the ABusVars global variable (discussed in the AppleTalk Manager chapter of Volume II), the PGetAppleTalkInfo function returns • a pointer to the .MPP driver’s device control entry data structure (DCE) • configuration flags, which indicate the status of certain conditions that are set at startup • a value (the selfSend flag) that indicates whether the node can send packets to itself • the network number range for the network to which the node is attached • the 8-bit node ID and 16-bit network number of the node • the 8-bit node ID and 16-bit network number of the last router from which the node has heard • the maximum capacities of the .MPP driver—such as the maximum number of protocol handlers and the maximum number of static sockets allowed by this driver • a pointer to the registered names queue • the node address of the node on the underlying data link (for example, the Ethernet hardware address) • the node’s zone name The data link address (for example, the Ethernet hardware address) and the zone name are returned only for extended networks; that is, network types that allow more than one network per cable. You must allocate memory for and provide pointers to the data buffers into which the PGetAppleTalkInfo function returns the data link address and zone name. You use the laLength parameter to specify the length of the data link address you want returned; the function returns the actual length of the data in the laLength parameter and returns the data in the buffer you provide. Note: Always use the PGetAppleTalkInfo function to obtain information about the .MPP driver. You can no longer rely on the validity of the global variables described in the AppleTalk chapter of Inside Macintosh, Volume II. FUNCTION PGetAppleTalkInfo (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr; Parameter block ¨ 16 ioResult word result code Æ 26 csCode word always PGetAppleTalkInfo Æ 28 version word version of function ¨ 30 varsPtr pointer pointer to MPP globals ¨ 34 dcePtr pointer pointer to DCE for .MPP ¨ 38 portID word port number ¨ 40 configuration long configuration flags ¨ 44 selfSend word nonzero if self-send is enabled ¨ 46 netLo word low value of the network range ¨ 48 netHi word high value of the network range ¨ 50 ourAddr long local 24-bit AppleTalk address ¨ 54 routerAddr long 24-bit address of router ¨ 58 numOfPHs word max number of protocol handlers ¨ 60 numOfSkts word max number of static sockets ¨ 62 numNBPEs word max concurrent NBP requests ¨ 64 ntQueue pointer pointer to registered name queue ´ 68 laLength word length in bytes of data link address (extended networks only) Æ 70 linkAddr pointer pointer to data link address buffer (extended networks only) Æ 74 zoneName pointer pointer to zone name buffer The PGetAppleTalkInfo function returns information about the .MPP driver. If the node on which your program is running happens also to be running AppleTalk Internet Router software in the background, there may be more than one set of .MPP global variables in RAM. To make sure you are obtaining information about the .MPP driver that handles application software, always use the PGetAppleTalkInfo function rather than the Device Manager’s PBControl function. If you are using assembly language, or want to use the PBControl function, you must use a device driver reference number of –10 for the .MPP driver. Parameters ioResult The result of the function. When you execute the function asynchronously, the function sets this parameter to 1 and returns a function result of noErr as soon as the function begins execution. When the function completes execution, it sets the ioResult parameter to the actual result code. csCode Routine selector, automatically set by the MPW interface. Always equal to PGetAppleTalkInfo for this function. version The version number of the PGetAppleTalkInfo function you are calling. For version number 53 of the .MPP driver, this number is always 1. varsPtr A pointer to the MPP global variables. The MPP global variables are discussed in “Protocol Handlers and Socket Listeners” in Chapter 10 of Volume II. dcePtr A pointer to the device control entry (DCE) data structure for the .MPP driver. The DCE is described in the Device Manager chapters of Volumes II and V. portID The port number for the .MPP driver. The port number is always 0 unless you are requesting information for an .MPP driver being used by a router. configuration A 32-bit long word of configuration flags. The following flags are currently defined: Bit Flag Description 31 SrvAdrBit TRUE (1) if the routine that opened the .MPP driver requested a server node number. Server node numbers are described in the AppleTalk Manager of Volume V. This flag indicates only that the server-node number was requested, not that it was returned. Some AppleTalk devices, such as EtherTalk, do not honor a request for a server-node number. 30 RouterBit TRUE (1) if an AppleTalk Internet Router was loaded at system startup (that is, there's a router operating on the same node as your application). A router can be loaded but not active. 15 ExtendedBit TRUE (1) if the node is on an extended network. 7 BadZoneHintBit TRUE (1) if the zone name of the node you are on was not the same as the zone name stored in parameter RAM (sometimes referred to as the zone name hint) when the .MPP driver was opened. If the zone name hint is invalid, then the AppleTalk Manager uses the default zone for the network. 6 OneZoneBit TRUE (1) if only one zone is assigned to your extended network or if you are not on an extended network. selfSend This parameter is nonzero if the ability of a node to send packets to itself is enabled. Use the PSetSelfSend function, described in the AppleTalk Manager chapter of Volume V, to enable or disable this feature. netLo The low value of the range of network numbers on the local cable. Only extended networks can have a range of network numbers. For a nonextended network, this parameter returns the network number. netHi The high value of the range of network numbers on the local cable. Only extended networks can have a range of network numbers. For a nonextended network, this parameter returns the network number. ourAddr The 24-bit AppleTalk network address of the node you are on. The least significant byte of the longword is the node ID. The middle 16 bits are the network number. The most significant byte of the longword is reserved for use by Apple Computer, Inc. routerAddr The 24-bit AppleTalk network address of the last router from which your node heard traffic. The least significant byte of the longword is the node ID. The middle 16 bits are the network number. The most significant byte of the longword is reserved for use by Apple Computer, Inc. You should always use this address when you want to communicate with a router. numOfPHs The maximum number of protocol handlers that this .MPP driver allows. numOfSkts The maximum number of statically assigned sockets that this .MPP driver allows. Statically assigned sockets are described in Inside AppleTalk. numNBPEs The maximum number of concurrent requests to NBP that this .MPP driver allows. ntQueue A pointer to the first entry in the names table for the local node. You can use NBP routines to look up and register names in the names table. The names table is described in “Name-Binding Protocol” in Chapter 10 of Volume II. laLength When you call the PGetAppleTalkInfo function on a node on an extended network, you use this parameter to specify the number of bytes of the data link address the function should place in the buffer pointed to by the LinkAddr parameter. If you request more bytes than the total number of bytes in the address, then the function returns in the laLength parameter the actual number of bytes it placed in the buffer. If the address is longer than the size of the buffer, then the PGetAppleTalkInfo function fills the buffer and returns in the laLength parameter the actual length of the address, not the number of bytes returned. The function does not return an error when the buffer is too large or too small for the address. linkAddr A pointer to a buffer for the data link address returned for extended networks only. You use the laLength parameter to specify the number of bytes of the address that you want placed in this buffer. You must allocate a buffer large enough to hold the number of bytes you specify. Speficy NIL for this parameter if you do not want the function to provide a data-link address. zoneName A pointer to a buffer into which the PGetAppleTalkInfo function places the local node’s zone name. You must allocate a buffer of at least 33 bytes to hold this data, or specify NIL for the ZoneName parameter if you do not want to obtain the zone name. This field is returned only if the node is on an extended network. Result codes noErr 0 no error æKY PATalkClosePrep æFp AppleTalk.p æT FUNCTION æD FUNCTION PATalkClosePrep(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PATalkClosePrep(thePBptr,async); æRI VI æC Whereas it is unlikely that opening the .MPP driver will adversely affect another program, an application should never close the .MPP driver, because another program might be using it. Under certain circumstances, however, the system might close the .MPP driver, provided no application objects. The system uses the .MPP driver’s PATalkClosePrep function to inform each routine in the AppleTalk Transition Queue that it intends to close the .MPP driver, giving each routine in the queue the opportunity to deny permission to do so. The system provides a pointer to a 255-byte buffer when it calls the PATalkClosePrep function. If any routine in the AppleTalk Transition Queue denies permission to close the .MPP driver, it places a name in the buffer and returns control to the AppleTalk Manager. The name that the routine places in the buffer should be the name of the application that placed the entry in the queue. The PATalkClosePrep function then calls each routine in the AppleTalk Transition Queue a second time to inform it that the request to close the .MPP driver has been canceled. If any routine in the AppleTalk Transition Queue denies permission to close the .MPP driver, the PATalkClosePrep function returns the result code closeErr. If any routine denies permission to close the .MPP driver, the system displays a dialog box informing the user that another application is using the .MPP driver, and showing the name that the AppleTalk Transition Queue routine placed in the buffer. The dialog box gives the user the option of canceling the request to close AppleTalk, or of closing AppleTalk anyway. Note: If the user chooses to close AppleTalk despite the fact that an application is using it, the system calls the MPPClose function. AppleTalk calls each application in the AppleTalk Transition Queue again, this time informing it that AppleTalk is about to close. In this case, your AppleTalk Transition Queue routine must prepare for the imminent closing of AppleTalk; it cannot deny permission to the MPPClose function. FUNCTION PATalkClosePrep (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr; Parameter block Æ 26 csCode word always PATalkClosePrep Æ appName pointer buffer for name of application that denies request The PATalkClosePrep function calls each routine listed in the AppleTalk Transition Queue to request permission to close the .MPP driver. The routine that calls the PATalkClosePrep function must allocate a 255-byte buffer and provide a pointer to it in the appName parameter. If a routine in the AppleTalk Transition Queue denies permission to close the .MPP driver, that routine places a name in the buffer pointed to by the appName parameter, and the AppleTalk Manager calls each routine in the AppleTalk Transition Queue a second time to inform it that the request to close the .MPP driver has been canceled. The PATalkClosePrep function then returns the result code closeErr, indicating that the calling routine may not close the .MPP driver. The csCode parameter is a routine selector; it is always equal to PATalkClosePrep for this function. Result codes noErr 0 no error closeErr –24 permission to close .MPP driver was denied æKY PCancelATalkClosePrep æFp AppleTalk.p æT FUNCTION æD FUNCTION PCancelATalkClosePrep(thePBptr: MPPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PCancelATalkClosePrep(thePBptr,async); æRI VI æC The system can use the PCancelATClosePrep function to undo the effects of the PATalkClosePrep function. The system uses this function, for example, if some condition prevents it from closing the .MPP driver even though each routine listed in the AppleTalk Transition Queue gave permission to close it. When the system calls the PCancelATClosePrep function, the AppleTalk Manager calls each routine in the AppleTalk Transition Queue to inform it that the request to close the .MPP driver has been canceled. FUNCTION PCancelATClosePrep (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr; Parameter block Æ 26 csCode word always PCancelATClosePrep The PCancelATClosePrep function undoes the effects of the PATalkClosePrep function. The PCancelATClosePrep function calls each routine in the AppleTalk Transition Queue to inform it that the request to close the .MPP driver has been canceled. The operating system uses this function, for example, if some condition prevents it from closing the .MPP driver even though each routine listed in the AppleTalk Transition Queue gave permission to close it. The csCode parameter is a routine selector, always equal to PCancelATClosePrep for this function. Result codes noErr 0 no error æKY POpenATPSkt æFp AppleTalk.p æT FUNCTION æD FUNCTION POpenATPSkt(thePBptr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := POpenATPSkt(thePBptr,async); æRI II-315,V-513 æC OpenATPSkt function Parameter block -> 26 csCode word ;always openATPSkt <-> 28 atpSocket byte ;socket number -> 30 addrBlock long word ;socket request specification OpenATPSkt opens a socket for the purpose of receiving requests. ATPSocket contains the socket number of the socket to open. If it's 0, a number is dynamically assigned and returned in atpSocket. AddrBlock contains a specification of the socket addresses from which requests will be accepted. A 0 in the network number, node ID, or socket number field of addrBlock means that requests will be accepted from every network, node, or socket, respectively. Result codes noErr No error tooManySkts Too many responding sockets noDataArea Too many outstanding ATP calls æKY PCloseATPSkt æFp AppleTalk.p æT FUNCTION æD FUNCTION PCloseATPSkt(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PCloseATPSkt(thePBPtr,async); æRI II-316,V-513 æC CloseATPSkt function Parameter block -> 26 csCode word ;always closeATPSkt -> 28 atpSocket byte ;socket number CloseATPSkt closes the socket whose number is specified by atpSocket, for the purpose of receiving requests. Result codes noErr No error æKY PSendRequest æFp AppleTalk.p æT FUNCTION æD FUNCTION PSendRequest(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PSendRequest(thePBPtr,async); æRI II-316,V-513 æC SendRequest function Parameter block -> 18 userData long word ;user bytes <- 22 reqTID word ;transaction ID used in request -> 26 csCode word ;always sendRequest <- 28 currBitMap byte ;bit map <-> 29 atpFlags byte ;control information -> 30 addrBlock long word ;destination socket address -> 34 reqLength word ;request size in bytes -> 36 reqPointer pointer ;pointer to request data -> 40 bdsPointer pointer ;pointer to response BDS -> 44 numOfBuffs byte ;number of responses expected -> 45 timeOutVal byte ;timeout interval <- 46 numOfResps byte ;number of responses received <-> 47 retryCount byte ;number of retries SendRequest sends a request to another socket and waits for a response. UserData contains the four user bytes. AddrBlock indicates the socket to which the request should be sent. ReqLength and reqPointer contain the size and location of the request to send. BDSPointer points to a response BDS where the responses are to be returned; numOfBuffs indicates the number of responses requested. The number of responses received is returned in numOfResps. If a nonzero value is returned in numOfResps, you can examine currBitMap to determine which packets of the transaction were actually received and to detect pieces for higher-level recovery, if desired. TimeOutVal indicates the number of seconds that SendRequest should wait for a response before resending the request. RetryCount indicates the maximum number of retries SendRequest should attempt. The end-of-message flag of atpFlags will be set if the EOM bit is set in the last packet received in a valid response sequence. The exactly-once flag should be set if you want the request to be part of an exactly-once transaction. To cancel a SendRequest call, you need the transaction ID; it's returned in reqTID. You can examine reqTID before the completion of the call, but its contents are valid only after the tidValid bit of atpFlags has been set. SendRequest completes when either an entire response is received or the retry count is exceeded. Note: The value provided in retryCount will be modified during SendRequest if any retries are made. This field is used to monitor the number of retries; for each retry, it's decremented by 1. Result codes noErr No error reqFailed Retry count exceeded tooManyReqs Too many concurrent requests noDataArea Too many outstanding ATP calls reqAborted Request canceled by user æKY PGetRequest æFp AppleTalk.p æT FUNCTION æD FUNCTION PGetRequest(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PGetRequest(thePBPtr,async); æRI II-317,V-513 æC GetRequest function Parameter block <- 18 userData long word ;user bytes -> 26 csCode word ;always getRequest -> 28 atpSocket byte ;socket number <- 29 atpFlags byte ;control information <- 30 addrBlock long word ;source of request <-> 34 reqLength word ;request buffer size -> 36 reqPointer pointer ;pointer to request buffer <- 44 bitMap byte ;bit map <- 46 transID word ;transaction ID GetRequest sets up the mechanism to receive a request sent by a SendRequest call. UserData returns the four user bytes from the request. ATPSocket contains the socket number of the socket that should listen for a request. The internet address of the socket from which the request was sent is returned in addrBlock. ReqLength and reqPointer indicate the size (in bytes) and location of a buffer to store the incoming request. The actual size of the request is returned in reqLength. The transaction bit map and transaction ID will be returned in bitMap and transID. The exactly-once flag in atpFlags will be set if the request is part of an exactly-once transaction. GetRequest completes when a request is received. Result codes noErr No error badATPSkt Bad responding socket æKY PSendResponse æFp AppleTalk.p æT FUNCTION æD FUNCTION PSendResponse(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PSendResponse(thePBPtr,async); æRI II-317,V-513 æC SendResponse function Parameter block <- 18 userData long word ;user bytes from TRel <- 22 reqTID word ;transaction ID used in request -> 26 csCode word ;always sendResponse -> 28 atpSocket byte ;socket number -> 29 atpFlags byte ;control information -> 30 addrBlock long word ;response destination -> 40 bdsPointer pointer ;pointer to response BDS -> 44 numOfBuffs byte ;number of response packets being sent -> 45 bdsSize byte ;BDS size in elements -> 46 transID word ;transaction ID SendResponse sends a response to a socket. If the response was part of an exactly- once transaction, userData will contain the user bytes from the TRel packet. ATPSocket contains the socket number from which the response should be sent. The end-of-message flag in atpFlags should be set if the response contains the final packet in a transaction composed of a group of packets and the number of responses is less than requested. AddrBlock indicates the address of the socket to which the response should be sent. BDSPointer points to a response BDS containing room for the maximum number of responses to be sent; bdsSize contains this maximum number. NumOfBuffs contains the number of response packets to be sent in this call; you may wish to make AddResponse calls to complete the response. TransID indicates the transaction ID of the associated request. During exactly-once transactions, SendResponse doesn't complete until either a TRel packet is received from the socket that made the request, or the retry count is exceeded. Result codes noErr No error badATPSkt Bad responding socket noRelErr No release received noDataArea Too many outstanding ATP calls badBuffNum Sequence number out of range æKY PAddResponse æFp AppleTalk.p æT FUNCTION æD FUNCTION PAddResponse(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PAddResponse(thePBPtr,async); æRI II-318,V-513 æC AddResponse function Parameter block -> 18 userData long word ;user bytes -> 26 csCode word ;always addResponse -> 28 atpSocket byte ;socket number -> 29 atpFlags byte ;control information -> 30 addrBlock long word ;response destination -> 34 reqLength word ;response size -> 36 reqPointer pointer ;pointer to response -> 44 rspNum byte ;sequence number -> 46 transID word ;transaction ID AddResponse sends an additional response packet to a socket that has already been sent the initial part of a response via SendResponse. UserData contains the four user bytes. ATPSocket contains the socket number from which the response should be sent. The end-of-message flag in atpFlags should be set if this response packet is the final packet in a transaction composed of a group of packets and the number of responses is less than requested. AddrBlock indicates the socket to which the response should be sent. ReqLength and reqPointer contain the size (in bytes) and location of the response to send; rspNum indicates the sequence number of the response (in the range 0 to 7). TransID must contain the transaction ID. Warning: If the transaction is part of an exactly-once transaction, the buffer used in the AddResponse call must not be altered or released until the corresponding SendResponse call has completed. Result codes noErr No error badATPSkt Bad responding socket noSendResp AddResponse issued before SendResponse badBuffNum Sequence number out of range noDataArea Too many outstanding ATP calls æKY PRelTCB æFp AppleTalk.p æT FUNCTION æD FUNCTION PRelTCB(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PRelTCB(thePBPtr,async); æRI II-319,V-513 æC RelTCB function Parameter block -> 26 csCode word ;always relTCB -> 30 addrBlock long word ;destination of request -> 46 transID word ;transaction ID of request RelTCB dequeues the specified SendRequest call and returns the result code reqAborted for the aborted call. The transaction ID can be obtained from the reqTID field of the SendRequest queue entry; see the description of SendRequest for details. Result codes noErr No error cbNotFound ATP control block not found noDataArea Too many outstanding ATP calls æKY PRelRspCB æFp AppleTalk.p æT FUNCTION æD FUNCTION PRelRspCB(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PRelRspCB(thePBPtr,async); æRI II-319,V-514 æC RelRspCB function Parameter block -> 26 csCode word ;always relRspCB -> 28 atpSocket byte ;socket number that request was received on -> 30 addrBlock long word ;source of request -> 46 transID word ;transaction ID of request In an exactly-once transaction, RelRspCB cancels the specified SendResponse, without waiting for the release timer to expire or a TRel packet to be received. No error is returned for the SendResponse call. Whan called to cancel a transaction that isn't using exactly-once service, RelRspCB returns cbNotFound. The transaction ID can be obtained from the reqTID field of the SendResponse queue entry; see the description of SendResponse for details. Result codes noErr No error cbNotFound ATP control block not found æKY PNSendRequest æFp AppleTalk.p æT FUNCTION æD FUNCTION PNSendRequest(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PNSendRequest(thePBPtr,async); æRI V-516 æC »Sending an ATP Request Through a Specified Socket ATP requests can now be sent through client-specified sockets. ATP previously would open a dynamic socket, send the request through it, and close the socket when the request was completed. The client can now choose to send a request through an already-opened socket; this also allows more than one request to be sent per socket. A new call, PNSendRequest, has been added for this purpose. The function of the old SendRequest call itself remains unchanged. FUNCTION PNSendRequest (thePBptr: ATPBPtr; async: BOOLEAN) : OSErr; Parameter block --> 18 userData longword User bytes <-- 22 reqTID word Transaction ID used in request --> 26 csCode word Always sendRequest <-> 28 atpSocket byte Socket to send request on or current bitmap <-> 29 atpFlags byte Control information --> 30 addrBlock longword Destination socket address --> 34 reqLength word Request size in bytes --> 36 reqPointer pointer Pointer to request data --> 40 bdsPointer pointer Pointer to response BDS --> 44 numOfBuffs byte Number of responses expected --> 45 timeOutVal byte Timeout interval <-- 46 numOf Resps byte Number of responses received <-> 47 retryCount byte Number of retries <-- 48 intBuff word Used internally The PNSendRequest call is functionally equivalent to the SendRequest call, however PNSendRequest allows you to specify, in the atpSocket field, the socket through which the request is to be sent. This socket must have been previously opened through an OpenATPSkt request (otherwise a badATPSkt error will be returned). Note that PNSendRequest requires two additional bytes of memory at the end of the parameter block, immediately following the retryCount. These bytes are for the internal use of the AppleTalk Manager and should not be modified while the PNSendRequest call is active. There is a machine-dependent limit as to the number of concurrent PNSendRequests that can be active on a given socket. If this limit is exceeded, the error tooManyReqs is returned. One additional difference between SendRequest and PNSendRequest is that a PNSendRequest can only be aborted by a PKillSendReq call (see below), whereas a SendRequest can be aborted by either a RelTCB or KillSendReq call. Result Codes noErr No error reqFailed Retry count exceeded tooManyReqs Too many concurrent requests noDataArea Too many outstanding ATP calls reqAborted Request cancelled by user æKY PKillSendReq æFp AppleTalk.p æT FUNCTION æD FUNCTION PKillSendReq(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PKillSendReq(thePBPtr,async); æRI V-517 æC »Aborting ATP SendRequests The RelTCB call is still supported, but only for aborting SendRequests. To abort PNSendRequests, a new call, PKillSendReq, has been added. This call will abort both SendRequests and PNSendRequests. PKillSendReq’s only argument is the queue element pointer of the request to be aborted. The queue element pointer is passed at the offset of the PKillSendReq queue element specified by aKillQE1. FUNCTION PKillSendReq (thePBptr: ATPPBPtr; async: BOOLEAN) : OSErr; Parameter block --> 26 csCode word Always PKillSendReq --> 44 aKillQEl pointer Pointer to queue element PKillSendReq is functionally equivalent to RelTCB, except that it takes different arguments and will abort both SendRequests and PNSendRequests. To abort one of these calls, place a pointer to the queue element of the call to abort in aKillQEl and issue the PKillSendReq call. Result Codes noErr No error cbNotFound aKillQEl does not point to a SendReq or NSendReq queue element æKY PKillGetReq æFp AppleTalk.p æT FUNCTION æD FUNCTION PKillGetReq(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PKillGetReq(thePBPtr,async); æRI V-518 æC »Aborting ATP GetRequests ATP GetRequests can now be aborted through the PKillGetReq call. This call looks and works just like the PKillSendReq call, and is used to abort a specific GetRequest call. Previously it was necessary to close the socket to abort all GetRequest calls on the socket. FUNCTION PKillGetReq (thePBptr: ATPPBPtr; async: BOOLEAN) : OSErr; Parameter block --> 26 csCode word Always PKillGetReq --> 44 aKillQEl pointer Pointer to queue element PKillGetReq will abort a specific outstanding GetRequest call (as opposed to closing the socket, which aborts all outstanding GetRequests on that socket). The call will be completed with a reqAborted error. To abort a GetRequest, place a pointer to the queue element of the call to abort in aKillQEl and issue the PKillGetReq call. Result Codes noErr No error cbNotFound aKillQEl does not point to a GetReq queue element æKY PKillAllGetReq æFp AppleTalk.p æT FUNCTION æD FUNCTION PKillAllGetReq(thePBPtr: ATPPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PKillAllGetReq(thePBPtr,async); æRI V-518 æC »Aborting ATP GetRequests ATP GetRequests can now be aborted through the PKillGetReq call. This call looks and works just like the PKillSendReq call, and is used to abort a specific GetRequest call. Previously it was necessary to close the socket to abort all GetRequest calls on the socket. FUNCTION PKillGetReq (thePBptr: ATPPBPtr; async: BOOLEAN) : OSErr; Parameter block --> 26 csCode word Always PKillGetReq --> 44 aKillQEl pointer Pointer to queue element PKillGetReq will abort a specific outstanding GetRequest call (as opposed to closing the socket, which aborts all outstanding GetRequests on that socket). The call will be completed with a reqAborted error. To abort a GetRequest, place a pointer to the queue element of the call to abort in aKillQEl and issue the PKillGetReq call. Result Codes noErr No error cbNotFound aKillQEl does not point to a GetReq queue element æKY BuildLAPwds æFp AppleTalk.p æT PROCEDURE æD PROCEDURE BuildLAPwds(wdsPtr: Ptr;dataPtr: Ptr;destHost: INTEGER;prototype: INTEGER; frameLen: INTEGER); æDT BuildLAPwds(wdsPtr,dataPtr,destHost,prototype,frameLen); æRI V-514 æC This routine builds a single-frame write data structure LAP WDS for use with the PWriteLAP call. Given a buffer of length frameLen pointed to by dataPtr, it fills in the WDS pointed to by wdsPtr and sets the destination node and protocol type as indicated by destHost and protoType, respectively. The WDS indicated must contain at least two elements. æKY BuildDDPwds æFp AppleTalk.p æT PROCEDURE æD PROCEDURE BuildDDPwds(wdsPtr: Ptr;headerPtr: Ptr;dataPtr: Ptr;netAddr: AddrBlock; ddpType: INTEGER;dataLen: INTEGER); æDT BuildDDPwds(wdsPtr,headerPtr,dataPtr,netAddr,ddpType,dataLen); æRI V-514 æC This routine builds a single-frame write data structure DDP WDS, for use with the PWriteDDP call. Given a header buffer of at least 17 bytes pointed to by headerPtr and a data buffer of length dataLen pointed to by dataPtr, it fills in the WDS pointed to by wdsPtr, and sets the destination address and protocol type as indicated by destaddress and DDPtype, respectively. The WDS indicated must contain at least 3 elements. æKY NBPSetEntity æFp AppleTalk.p æT PROCEDURE æD PROCEDURE NBPSetEntity(buffer: Ptr;nbpObject: Str32;nbpType: Str32;nbpZone: Str32); æDT NBPSetEntity(buffer,nbpObject,nbpType,nbpZone); æRI V-514 æC This routine builds an NBP entity structure, for use with the PLookupNBP and PConfirmName calls. Given a buffer of at least the size of the EntityName data structure (99 bytes) pointed to by buffer, this routine sets the indicated object, type, and zone in that buffer. æKY NBPSetNTE æFp AppleTalk.p æT PROCEDURE æD PROCEDURE NBPSetNTE(ntePtr: Ptr;nbpObject: Str32;nbpType: Str32;nbpZone: Str32; socket: INTEGER); æDT NBPSetNTE(ntePtr,nbpObject,nbpType,nbpZone,socket); æRI V-515 æC This routine builds an NBP names table entry, for use with the PRegisterName call. Given a names table entry of at least the size of the EntityName data structure plus nine bytes (108 bytes) pointed to by ntePtr, this routine sets the indicated object, type, zone, and socket in that names table entry. æKY GetBridgeAddress æFp AppleTalk.p æT FUNCTION æD FUNCTION GetBridgeAddress: INTEGER; æDT myVariable := GetBridgeAddress; æRT 132 æRI V-515, N132-2 æC This routine returns the current address of a bridge in the low byte, or zero if there is none. æKY BuildBDS æFp AppleTalk.p æT FUNCTION æD FUNCTION BuildBDS(buffPtr: Ptr;bdsPtr: Ptr;buffSize: INTEGER): INTEGER; æDT myVariable := BuildBDS(buffPtr,bdsPtr,buffSize); æRI V-515 æC This routine builds a BDS, for use with the ATP calls. Given a data buffer of length buffSize pointed to by buffPtr, it fills in the BDS pointed to by bdsPtr. The buffer will be broken up into pieces of maximum size (578 bytes). The user bytes in the BDS are not modified by this routine. This routine is provided only as a convenience; generally the caller will be able to build the BDS completely from Pascal without it. æKY MPPOpen æFp AppleTalk.p æT FUNCTION æD FUNCTION MPPOpen: OSErr; æDT myVariable := MPPOpen; æMM æRT 224 æRI II-275 æC MPPOpen first checks whether the .MPP driver has already been loaded; if it has, MPPOpen does nothing and returns noErr. If MPP hasn’t been loaded, MPPOpen attempts to load it into the system heap. If it succeeds, it then initializes the driver’s variables and goes through the process of dynamically assigning a node ID to that Macintosh. On a Macintosh 512K or XL, it also loads the .ATP driver and NBP code into the system heap. If serial port B isn’t configured for AppleTalk, or is already in use, the .MPP driver isn’t loaded and an appropriate result code is returned. Result codes noErr No error portInUse Port B is already in use portNotCf Port B not configured for AppleTalk æKY MPPClose æFp AppleTalk.p æT FUNCTION æD FUNCTION MPPClose: OSErr; æDT myVariable := MPPClose; æMM æRI II-275 æC MPPClose removes the .MPP driver, and any data structures associated with it, from memory. If the .ATP driver or NBP code were also installed, they’re removed as well. MPPClose also returns the use of port B to the Serial Driver. Warning: Since other co-resident programs may be using AppleTalk, it’s strongly recommended that you never use this call. MPPClose will completely disable AppleTalk; the only way to restore AppleTalk is to call MPPOpen again. æKY LAPOpenProtocol æFp AppleTalk.p æT FUNCTION æD FUNCTION LAPOpenProtocol(theLAPType: ABByte;protoPtr: Ptr): OSErr; æDT myVariable := LAPOpenProtocol(theLAPType,protoPtr); æMM æRI II-277 æC æKY LAPCloseProtocol æFp AppleTalk.p æT FUNCTION æD FUNCTION LAPCloseProtocol(theLAPType: ABByte): OSErr; æDT myVariable := LAPCloseProtocol(theLAPType); æMM æRI II-277 æC LAPCloseProtocol removes from the node’s protocol table the specified ALAP protocol type, as well as its protocol handler. Warning: Don’t close ALAP protocol type values 1 or 2. If you close these protocol types, DDP will be disabled; once disabled, the only way to restore DDP is to restart the system, or to close and then reopen AppleTalk. Result codes noErr No error lapProtErr Error detaching protocol type æKY LAPWrite æFp AppleTalk.p æT FUNCTION æD FUNCTION LAPWrite(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := LAPWrite(abRecord,async); æMM æRI II-277 æC ABusRecord <-- abOpcode {always tLAPWrite} <-- abResult {result code} --> abUserReference {for your use} --> lapAddress.dstNodeID {destination node ID} --> lapAddress.lapProtType {ALAP protocol type} --> lapReqCount {length of frame data} --> lapDataPtr {pointer to frame data} LAPWrite sends a frame to another node. LAPReqCount and lapDataPtr specify the length and location of the data to send. The lapAddress.lapProtType field indicates the ALAP protocol type of the frame and the lapAddress.dstNodeID indicates the node ID of the node to which the frame should be sent. Note: The first two bytes of an ALAP frame’s data must contain the length in bytes of that data, including the length bytes themselves. Result codes noErr No error excessCollsns Unable to contact destination node; packet not sent ddpLenErr ALAP data length too big lapProtErr Invalid ALAP protocol type æKY LAPRead æFp AppleTalk.p æT FUNCTION æD FUNCTION LAPRead(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := LAPRead(abRecord,async); æMM æRI II-278 æC ABusRecord <-- abOpcode {always tLAPRead} <-- abResult {result code} --> abUserReference {for your use} <-- lapAddress.dstNodeID {destination node ID} <-- lapAddress.srcNodeID {source node ID} --> lapAddress.lapProtType {ALAP protocol type} --> lapReqCount {buffer size in bytes} <-- lapActCount {number of frame data bytes actually received} --> lapDataPtr {pointer to buffer} LAPRead receives a frame from another node. LAPReqCount and lapDataPtr specify the size and location of the buffer that will receive the frame data. If the buffer isn’t large enough to hold all of the incoming frame data, the extra bytes will be discarded and buf2SmallErr will be returned. The number of bytes actually received is returned in lapActCount. Only frames with ALAP protocol type equal to lapAddress.lapProtType will be received. The node IDs of the frame’s source and destination nodes are returned in lapAddress.srcNodeID and lapAddress.dstNodeID. You can determine whether the packet was broadcast to you by examining the value of lapAddress.dstNodeID—if the packet was broadcast it’s equal to 255, otherwise it’s equal to your node ID. Note: You should issue LAPRead calls only for ALAP protocol types that were opened (via LAPOpenProtocol) to use the default protocol handler. Warning: If you close a protocol type for which there are still LAPRead calls pending, the calls will be canceled but the memory occupied by their ABusRecords will not be released. For this reason, before closing a protocol type, call LAPRdCancel to cancel any pending LAPRead calls associated with that protocol type. Result codes noErr No error buf2SmallErr Frame too large for buffer readQErr Invalid protocol type or protocol type not found in table æKY LAPRdCancel æFp AppleTalk.p æT FUNCTION æD FUNCTION LAPRdCancel(abRecord: ABRecHandle): OSErr; æDT myVariable := LAPRdCancel(abRecord); æMM æRI II-279 æC Given the handle to the ABusRecord of a previously made LAPRead call, LAPRdCancel dequeues the LAPRead call, provided that a packet satisfying the LAPRead has not already arrived. LAPRdCancel returns noErr if the LAPRead call is successfully removed from the queue. If LAPRdCancel returns recNotFnd, check the abResult field to verify that the LAPRead has been completed and determine its outcome. Result codes noErr No error readQErr Invalid protocol type or protocol type not found in table recNotFnd ABRecord not found in queue »Example This example sends an ALAP packet synchronously and waits asynchronously for a response. Assume that both nodes are using a known protocol type (in this case, 73) to receive packets, and that the destination node has a node ID of 4. VAR myABRecord: ABRecHandle; myBuffer: PACKED ARRAY [0..599] OF CHAR; {buffer for both send and receive} myLAPType: Byte; errCode, index, dataLen: INTEGER; someText: Str255; async: BOOLEAN; BEGIN errCode := MPPOpen; IF errCode <> noErr THEN WRITELN('Error in opening AppleTalk') {Maybe serial port B isn't available for use by AppleTalk} ELSE BEGIN {Call Memory Manager to allocate ABusRecord} myABRecord := ABRecHandle(NewHandle(lapSize)); myLAPType := 73; {Enter myLAPType into protocol handler table and install default handler to } { service frames of that ALAP type. No packets of that ALAP type will be } { received until we call LAPRead.} errCode := LAPOpenProtocol(myLAPType, NIL); IF errCode <> noErr THEN WRITELN('Error while opening the protocol type') {Have we opened too many protocol types? Remember that DDP uses two of } { them.} ELSE BEGIN {Prepare data to be sent} someText := 'This data will be in the ALAP data area'; {The .MPP implementation requires that the first two bytes of the ALAP } { data field contain the length of the data, including the length bytes } { themselves.} dataLen := LENGTH(someText) + 2; buffer[0] := CHR(dataLen DIV 256); {high byte of data length} buffer[1] := CHR(dataLen MOD 256); {low byte of data length} FOR index := 1 TO dataLen - 2 DO {stuff buffer with packet data} buffer[index + 1] := someText[index]; async := FALSE; WITH myABRecord^^ DO {fill parameters in the ABusRecord} BEGIN lapAddress.lapProtType := myLAPType; lapAddress.dstNodeID := 4; lapReqCount := dataLen; lapDataPtr := @buffer; END; {Send the frame} errCode := LAPWrite(myABRecord, async); {In the case of a sync call, errCode and the abResult field of } { the myABRecord will contain the same result code. We can also } { reuse myABRecord, since we know whether the call has completed.} IF errCode <> noErr THEN WRITELN('Error while writing out the packet') {Maybe the receiving node wasn't on-line} ELSE BEGIN {We have sent out the packet and are now waiting for a response. We } { issue an async LAPRead call so that we don't “hang” waiting for a } { response that may not come.} async := TRUE; WITH myABRecord^^ DO BEGIN lapAddress.lapProtType := myLAPType; {ALAP type we want to receive } lapReqCount := 600; {our buffer is maximum size} lapDataPtr := @buffer; END; errCode := LAPRead(myABRecord, async); {wait for a packet} IF errCode <> noErr THEN WRITELN('Error while trying to queue up a LAPRead') {Was the protocol handler installed correctly?} ELSE BEGIN {We can either sit here in a loop and poll the abResult } { field or just exit our code and use the event } { mechanism to flag us when the packet arrives.} CheckForMyEvent; {your procedure for checking for a network event} errCode := LAPCloseProtocol(myLAPType); IF errCode <> noErr THEN WRITELN('Error while closing the protocol type'); END; END; END; END; END. æKY DDPOpenSocket æFp AppleTalk.p æT FUNCTION æD FUNCTION DDPOpenSocket(VAR theSocket: Byte;sktListener: Ptr): OSErr; æDT myVariable := DDPOpenSocket(theSocket,sktListener); æMM æRI II-282 æC DDPOpenSocket adds a socket and its socket listener to the socket table. If theSocket is nonzero, it must be in the range 64 to 127, and it specifies the socket’s number; if theSocket is 0, DDPOpenSocket dynamically assigns a socket number in the range 128 to 254, and returns it in theSocket. SktListener contains a pointer to the socket listener; if it’s NIL, the default listener will be used. If you’re using the default socket listener, you must then call DDPRead to receive a datagram (in order to specify buffer space for the default socket listener). If, however, you’ve written your own socket listener and sktListener points to it, your listener will provide buffers for receiving datagrams and you shouldn’t use DDPRead calls. DDPOpenSocket will return ddpSktErr if you pass the number of an already opened socket, if you pass a socket number greater than 127, or if the socket table is full. Note: The range of static socket numbers 1 through 63 is reserved by Apple for internal use. Socket numbers 64 through 127 are available for unrestricted experimental use. Result codes noErr No error ddpSktErr Socket error æKY DDPCloseSocket æFp AppleTalk.p æT FUNCTION æD FUNCTION DDPCloseSocket(theSocket: Byte): OSErr; æDT myVariable := DDPCloseSocket(theSocket); æMM æRI II-282 æC æKY DDPRead æFp AppleTalk.p æT FUNCTION æD FUNCTION DDPRead(abRecord: ABRecHandle;retCksumErrs: BOOLEAN;async: BOOLEAN): OSErr; æDT myVariable := DDPRead(abRecord,retCksumErrs,async); æMM æRI II-283 æC ABusRecord <-- abOpcode {always tDDPRead} <-- abResult {result code} --> abUserReference {for your use} <-- ddpType {DDP protocol type} --> ddpSocket {listening socket number} <-- ddpAddress {source socket address} --> ddpReqCount {buffer size in bytes} <-- ddpActCount {number of bytes actually received} --> ddpDataPtr {pointer to buffer} <-- ddpNodeID {original destination node ID} DDPRead receives a datagram from another socket. The size and location of the buffer that will receive the data are specified by ddpReqCount and ddpDataPtr. If the buffer isn’t large enough to hold all of the incoming frame data, the extra bytes will be discarded and buf2SmallErr will be returned. The number of bytes actually received is returned in ddpActCount. DDPSocket specifies the socket to receive the datagram (the “listening” socket). The node to which the packet was sent is returned in ddpNodeID; if the packet was broadcast ddpNodeID will contain 255. The address of the socket that sent the packet is returned in ddpAddress. If retCksumErrs is FALSE, DDPRead will discard any packets received with an invalid checksum and inform the caller of the error. If retCksumErrs is TRUE, DDPRead will deliver all packets, whether or not the checksum is valid; it will also notify the caller when there’s a checksum error. Note: The sender of the datagram must be in a different node from the receiver. You should issue DDPRead calls only for receiving datagrams for sockets opened with the default socket listener; see the description of DDPOpenSocket. Note: If the buffer provided isn’t large enough to hold all of the incoming frame data (buf2SmallErr), the checksum can’t be calculated; in this case, DDPRead will deliver packets even if retCksumErrs is FALSE. Result codes noErr No error buf2SmallErr Datagram too large for buffer cksumErr Checksum error ddpLenErr Datagram length too big ddpSktErr Socket error readQErr Invalid socket or socket not found in table æKY DDPWrite æFp AppleTalk.p æT FUNCTION æD FUNCTION DDPWrite(abRecord: ABRecHandle;doChecksum: BOOLEAN;async: BOOLEAN): OSErr; æDT myVariable := DDPWrite(abRecord,doChecksum,async); æMM æRI II-283 æC ABusRecord <-- abOpcode {always tDDPWrite} <-- abResult {result code} --> abUserReference {for your use} --> ddpType {DDP protocol type} --> ddpSocket {source socket number} --> ddpAddress {destination socket address} --> ddpReqCount {length of datagram data} --> ddpDataPtr {pointer to buffer} DDPWrite sends a datagram to another socket. DDPReqCount and ddpDataPtr specify the length and location of the data to send. The ddpType field indicates the DDP protocol type of the frame, and ddpAddress is the complete internet address of the socket to which the datagram should be sent. DDPSocket specifies the socket from which the datagram should be sent. Datagrams sent over the internet to a node on an AppleTalk network different from the sending node’s network have an optional software checksum to detect errors that might occur inside the intermediate bridges. If doChecksum is TRUE, DDPWrite will compute this checksum; if it’s FALSE, this software checksum feature is ignored. Note: The destination socket can’t be in the same node as the program making the DDPWrite call. Result codes noErr No error ddpLenErr Datagram length too big ddpSktErr Source socket not open noBridgeErr No bridge found æKY DDPRdCancel æFp AppleTalk.p æT FUNCTION æD FUNCTION DDPRdCancel(abRecord: ABRecHandle): OSErr; æDT myVariable := DDPRdCancel(abRecord); æMM æRI II-284 æC Given the handle to the ABusRecord of a previously made DDPRead call, DDPRdCancel dequeues the DDPRead call, provided that a packet satisfying the DDPRead hasn’t already arrived. DDPRdCancel returns noErr if the DDPRead call is successfully removed from the queue. If DDPRdCancel returns recNotFnd, check the abResult field of abRecord to verify that the DDPRead has been completed and determine its outcome. Result codes noErr No error readQErr Invalid socket or socket not found in table recNotFnd ABRecord not found in queue »Example This example sends a DDP packet synchronously and waits asynchronously for a response. Assume that both nodes are using a known socket number (in this case, 30) to receive packets. Normally, you would want to use NBP to look up your destination’s socket address. VAR myABRecord: ABRecHandle; myBuffer: PACKED ARRAY [0..599] OF CHAR; {buffer for both send and receive} mySocket: Byte; errCode, index, dataLen: INTEGER; someText: Str255; async, retCksumErrs, doChecksum: BOOLEAN; BEGIN errCode := MPPOpen; IF errCode <> noErr THEN WRITELN('Error in opening AppleTalk') {Maybe serial port B isn't available for use by AppleTalk} ELSE BEGIN {Call Memory Manager to allocate ABusRecord} myABRecord := ABRecHandle(NewHandle(ddpSize)); mySocket := 30; {Add mySocket to socket table and install default socket listener to service } { datagrams addressed to that socket. No packets addressed to mySocket will be } { received until we call DDPRead. } errCode := DDPOpenSocket(mySocket, NIL); IF errCode <> noErr THEN WRITELN('Error while opening the socket') {Have we opened too many socket listeners? Remember that DDP uses two of } { them.} ELSE BEGIN {Prepare data to be sent} someText := 'This is a sample datagram'; dataLen := LENGTH(someText); FOR index := 0 TO dataLen - 1 DO {stuff buffer with packet data} myBuffer[index] := someText[index + 1]; async := FALSE; WITH myABRecord^^ DO {fill the parameters in the ABusRecord} BEGIN ddpType := 5; ddpAddress.aNet := 0; {send on “our” network} ddpAddress.aNode := 34; ddpAddress.aSocket := mySocket; ddpReqCount := dataLen; ddpDataPtr := @myBuffer; END; doChecksum := FALSE; {If packet contains a DDP long header, compute checksum and insert it into } { the header.} errCode := DDPWrite(myABRecord, doChecksum, async); {send packet} {In the case of a sync call, errCode and the abResult field of myABRecord } { will contain the same result code. We can also reuse myABRecord, since we } { know whether the call has completed.} IF errCode <> noErr THEN WRITELN('Error while writing out the packet') {Maybe the receiving node wasn't on-line} ELSE BEGIN {We have sent out the packet and are now waiting for a response. We } { issue an async DDPRead call so that we don't “hang” waiting for a } { response that may not come. To cancel the async read call, we must } { close the socket associated with the call or call DDPRdCancel.} async := TRUE; retCksumErrs := TRUE; {return packets even if } { they have a checksum error} WITH myABRecord^^ DO BEGIN ddpSocket := mySocket; ddpReqCount := 600; {our reception buffer is max size} ddpDataPtr := @myBuffer; END; {Wait for a packet asynchronously} errCode := DDPRead(myABRecord, retCksumErrs, async); IF errCode <> noErr THEN WRITELN('Error while trying to queue up a DDPRead') {Was the socket listener installed correctly?} ELSE BEGIN {We can either sit here in a loop and poll the } { abResult field or just exit our code and use the } { event mechanism to flag us when the packet arrives.} CheckForMyEvent; {your procedure for checking for a } { network event} {If there were no errors, a packet is inside the array } { mybuffer, the length is in ddpActCount, and the } { address of the sending socket is in ddpAddress. } { Process the packet received here and report any errors.} errCode := DDPCloseSocket(mySocket); {we're done with it} IF errCode <> noErr THEN WRITELN('Error while closing the socket'); END; END; END; END; END. æKY ATPLoad æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPLoad: OSErr; æDT myVariable := ATPLoad; æMM æRT 20, 224 æRI II-290, N20-2 æC •••Refer to Technical Note #224:••• ATPLoad first verifies that the .MPP driver is loaded and running. If it isn’t, ATPLoad verifies that port B is configured for AppleTalk and isn’t in use, and then loads MPP into the system heap. ATPLoad then loads the .ATP driver, unless it’s already in memory. On a Macintosh 128K, ATPLoad reads the .ATP driver from the system resource file into the application heap; on a Macintosh 512K or XL, ATP is read into the system heap. Note: On a Macintosh 512K or XL, ATPLoad and MPPOpen perform essentially the same function. Result codes noErr No error portInUse Port B is already in use portNotCf Port B not configured for AppleTalk æKY ATPUnload æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPUnload: OSErr; æDT myVariable := ATPUnload; æRI II-290 æC ATPUnload makes the .ATP driver purgeable; the space isn’t actually released by the Memory Manager until necessary. Note: This call applies only to a Macintosh 128K; on a Macintosh 512K or Macintosh XL, ATPUnload has no effect. Result codes noErr No error æKY ATPOpenSocket æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPOpenSocket(addrRcvd: AddrBlock;VAR atpSocket: Byte): OSErr; æDT myVariable := ATPOpenSocket(addrRcvd,atpSocket); æMM æRI II-290 æC ATPOpenSocket opens a socket for the purpose of receiving requests. ATPSocket contains the socket number of the socket to open; if it’s 0, a number is dynamically assigned and returned in atpSocket. AddrRcvd contains a filter of the sockets from which requests will be accepted. A 0 in the network number, node ID, or socket number field of the addrRcvd record acts as a “wild card”; for instance, a 0 in the socket number field means that requests will be accepted from all sockets in the node(s) specified by the network and node fields. Result codes noErr No error tooManySkts Socket table full noDataArea Too many outstanding ATP calls Note: If you’re only going to send requests and receive responses to these requests, you don’t need to open an ATP socket. When you make the ATPSndRequest or ATPRequest call, ATP automatically opens a dynamically assigned socket for that purpose. æKY ATPCloseSocket æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPCloseSocket(atpSocket: Byte): OSErr; æDT myVariable := ATPCloseSocket(atpSocket); æMM æRI II-291 æC ATPCloseSocket closes the responding socket whose number is specified by atpSocket. It releases the data structures associated with all pending, asynchronous calls involving that socket; these pending calls are completed immediately and return the result code sktClosed. Result codes noErr No error noDataArea Too many outstanding ATP calls æKY ATPSndRequest æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPSndRequest(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := ATPSndRequest(abRecord,async); æMM æRI II-291 æC ABusRecord <-- abOpcode {always tATPSndRequest} <-- abResult {result code} --> abUserReference {for your use} --> atpAddress {destination socket address} --> atpReqCount {request size in bytes} --> atpDataPtr {pointer to buffer} --> atpRspBDSPtr {pointer to response BDS} --> atpUserData {user bytes} --> atpXO {exactly-once flag} <-- atpEOM {end-of-message flag} --> atpTimeOut {retry timeout interval in seconds} --> atpRetries {maximum number of retries} --> atpNumBufs {number of elements in response BDS} <-- atpNumRsp {number of response packets actually received} ATPSndRequest sends a request to another socket. ATPAddress is the internet address of the socket to which the request should be sent. ATPDataPtr and atpReqCount specify the location and size of a buffer that contains the request information to be sent. ATPUserData contains the user bytes for the ATP header. ATPSndRequest requires you to allocate a response BDS. ATPRspBDSPtr is a pointer to the response BDS; atpNumBufs indicates the number of elements in the BDS (this is also the maximum number of response datagrams that will be accepted). The number of response datagrams actually received is returned in atpNumRsp; if a nonzero value is returned, you can examine the response BDS to determine which packets of the transaction were actually received. If the number returned is less than requested, one of the following is true: • Some of the packets have been lost and the retry count has been exceeded. • ATPEOM is TRUE; this means that the response consisted of fewer packets than were expected, but that all packets sent were received (the last packet came with the atpEOM flag set). ATPTimeOut indicates the length of time that ATPSndRequest should wait for a response before retransmitting the request. ATPRetries indicates the maximum number of retries ATPSndRequest should attempt. ATPXO should be TRUE if you want the request to be part of an exactly-once transaction. ATPSndRequest completes when either the transaction is completed or the retry count is exceeded. Result codes noErr No error reqFailed Retry count exceeded tooManyReqs Too many concurrent requests noDataArea Too many outstanding ATP calls æKY ATPRequest æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPRequest(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := ATPRequest(abRecord,async); æMM æRI II-292 æC ABusRecord <-- abOpcode {always tATPRequest} <-- abResult {result code} --> abUserReference {for your use} --> atpAddress {destination socket address} --> atpReqCount {request size in bytes} --> atpDataPtr {pointer to buffer} <-- atpActCount {number of bytes actually received} --> atpUserData {user bytes} --> atpXO {exactly-once flag} <-- atpEOM {end-of-message flag} --> atpTimeOut {retry timeout interval in seconds} --> atpRetries {maximum number of retries} <-- atpRspUData {user bytes received in transaction response} --> atpRspBuf {pointer to response message buffer} --> atpRspSize {size of response message buffer} ATPRequest is functionally analogous to ATPSndRequest. It sends a request to another socket, but doesn’t require the caller to set up and use the BDS data structure to describe the response buffers. ATPAddress indicates the socket to which the request should be sent. ATPDataPtr and atpReqCount specify the location and size of a buffer that contains the request information to be sent. ATPUserData contains the user bytes to be sent in the request’s ATP header. ATPTimeOut indicates the length of time that ATPRequest should wait for a response before retransmitting the request. ATPRetries indicates the maximum number of retries ATPRequest should attempt. To use this call, you must have an area of contiguous buffer space that’s large enough to receive all expected datagrams. The various datagrams will be assembled in this buffer and returned to you as a complete message upon completion of the transaction. The location and size of this buffer are passed in atpRspBuf and atpRspSize. Upon completion of the call, the size of the received response message is returned in atpActCount. The user bytes received in the ATP header of the first response packet are returned in atpRspUData. ATPXO should be TRUE if you want the request to be part of an exactly-once transaction. Although you don’t provide a BDS, ATPRequest in fact creates one and calls the .ATP driver (as in an ATPSndRequest call). For this reason, the abRecord fields atpRspBDSPtr and atpNumBufs are used by ATPRequest; you should not expect these fields to remain unaltered during or after the function’s execution. For ATPRequest to receive and correctly deliver the response as a single message, the responding end must, upon receiving the request (with an ATPGetRequest call), generate the complete response as a message in a single buffer and then call ATPResponse. Note: The responding end could also use ATPSndRsp and ATPAddRsp provided that each response packet (except the last one) contains exactly 578 ATP data bytes; the last packet in the response can contain less than 578 ATP data bytes. Also, if this method is used, only the ATP user bytes of the first response packet will be delivered to the requester; any information in the user bytes of the remaining response packets will not be delivered. ATPRequest completes when either the transaction is completed or the retry count is exceeded. Result codes noErr No error reqFailed Retry count exceeded tooManyReqs Too many concurrent requests sktClosed Socket closed by a cancel call noDataArea Too many outstanding ATP calls æKY ATPReqCancel æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPReqCancel(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := ATPReqCancel(abRecord,async); æMM æRI II-293 æC Given the handle to the ABusRecord of a previously made ATPSndRequest or ATPRequest call, ATPReqCancel dequeues the ATPSndRequest or ATPRequest call, provided that the call hasn’t already completed. ATPReqCancel returns noErr if the ATPSndRequest or ATPRequest call is successfully removed from the queue. If it returns cbNotFound, check the abResult field of abRecord to verify that the ATPSndRequest or ATPRequest call has completed and determine its outcome. Result codes noErr No error cbNotFound ATP control block not found æKY ATPGetRequest æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPGetRequest(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := ATPGetRequest(abRecord,async); æMM æRT 20 æRI II-293, N20-2 æC ABusRecord <-- abOpcode {always tATPGetRequest} <-- abResult {result code} --> abUserReference {for your use} --> atpSocket {listening socket number} <-- atpAddress {source socket address} --> atpReqCount {buffer size in bytes} --> atpDataPtr {pointer to buffer} <-- atpBitMap {transaction bit map} <-- atpTransID {transaction ID} <-- atpActCount {number of bytes actually received} <-- atpUserData {user bytes} <-- atpXO {exactly-once flag} ATPGetRequest sets up the mechanism to receive a request sent by either an ATPSndRequest or an ATPRequest call. ATPSocket contains the socket number of the socket that should listen for a request; this socket must already have been opened by calling ATPOpenSocket. The address of the socket from which the request was sent is returned in atpAddress. ATPDataPtr specifies a buffer to store the incoming request; atpReqCount indicates the size of the buffer in bytes. The number of bytes actually received in the request is returned in atpActCount. ATPUserData contains the user bytes from the ATP header. The transaction bit map is returned in atpBitMap. The transaction ID is returned in atpTransID. ATPXO will be TRUE if the request is part of an exactly-once transaction. ATPGetRequest completes when a request is received. To cancel an asynchronous ATPGetRequest call, you must call ATPCloseSocket, but this cancels all pending calls involving that socket. Result codes noErr No error badATPSkt Bad responding socket sktClosed Socket closed by a cancel call æKY ATPSndRsp æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPSndRsp(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := ATPSndRsp(abRecord,async); æMM æRI II-294 æC ABusRecord <-- abOpcode {always tATPSdRsp} <-- abResult {result code} --> abUserReference {for your use} --> atpSocket {responding socket number} --> atpAddress {destination socket address} --> atpRspBDSPtr {pointer to response BDS} --> atpTransID {transaction ID} --> atpEOM {end-of-message flag} --> atpNumBufs {number of response packets being sent} --> atpBDSSize {number of elements in response BDS} ATPSndRsp sends a response to another socket. ATPSocket contains the socket number from which the response should be sent and atpAddress contains the internet address of the socket to which the response should be sent. ATPTransID must contain the transaction ID. ATPEOM is TRUE if the response BDS contains the final packet in a transaction composed of a group of packets and the number of packets in the response is less than expected. ATPRspBDSPtr points to the buffer data structure containing the responses to be sent. ATPBDSSize indicates the number of elements in the response BDS, and must be in the range 1 to 8. ATPNumBufs indicates the number of response packets being sent with this call, and must be in the range 0 to 8. Note: In some situations, you may want to send only part (or possibly none) of your response message back immediately. For instance, you might be requested to send back seven disk blocks, but have only enough internal memory to store one block. In this case, set atpBDSSize to 7 (total number of response packets), atpNumBufs to 0 (number of response packets currently being sent), and call ATPSndRsp. Then as you read in one block at a time, call ATPAddRsp until all seven response datagrams have been sent. During exactly-once transactions, ATPSndRsp won’t complete until the release packet is received or the release timer expires. Result codes noErr No error badATPSkt Bad responding socket noRelErr No release received sktClosed Socket closed by a cancel call noDataArea Too many outstanding ATP calls badBuffNum Bad sequence number æKY ATPAddRsp æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPAddRsp(abRecord: ABRecHandle): OSErr; æDT myVariable := ATPAddRsp(abRecord); æMM æRI II-295 æC ABusRecord <-- abOpcode {always tATPAddRsp} <-- abResult {result code} --> abUserReference {for your use} --> atpSocket {responding socket number} --> atpAddress {destination socket address} --> atpReqCount {buffer size in bytes} --> atpDataPtr {pointer to buffer} --> atpTransID {transaction ID} --> atpUserData {user bytes} --> atpEOM {end-of-message flag} --> atpNumRsp {sequence number} ATPAddRsp sends one additional response packet to a socket that has already been sent the initial part of a response via ATPSndRsp. ATPSocket contains the socket number from which the response should be sent and atpAddress contains the internet address of the socket to which the response should be sent. ATPTransID must contain the transaction ID. ATPDataPtr and atpReqCount specify the location and size of a buffer that contains the information to send; atpNumRsp is the sequence number of the response. ATPEOM is TRUE if this response datagram is the final packet in a transaction composed of a group of packets. ATPUserData contains the user bytes to be sent in this response datagram’s ATP header. Note: No BDS is needed with ATPAddRsp because all pertinent information is passed within the record. Result codes noErr No error badATPSkt Bad responding socket badBuffNum Bad sequence number noSendResp ATPAddRsp issued before ATPSndRsp noDataArea Too many outstanding ATP calls æKY ATPResponse æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPResponse(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := ATPResponse(abRecord,async); æMM æRT 20 æRI II-296, N20-2 æC ABusRecord <-- abOpcode {always tATPResponse} <-- abResult {result code} --> abUserReference {for your use} --> atpSocket {responding socket number} --> atpAddress {destination socket address} --> atpTransID {transaction ID) --> atpRspUData {user bytes sent in transaction response} --> atpRspBuf {pointer to response message buffer} --> atpRspSize {size of response message buffer} ATPResponse is functionally analogous to ATPSndRsp. It sends a response to another socket, but doesn’t require the caller to provide a BDS. ATPAddress must contain the complete network address of the socket to which the response should be sent (taken from the data provided by an ATPGetRequest call). ATPTransID must contain the transaction ID. ATPSocket indicates the socket from which the response should be sent (the socket on which the corresponding ATPGetRequest was issued). ATPRspBuf points to the buffer containing the response message; the size of this buffer must be passed in atpRspSize. The four user bytes to be sent in the ATP header of the first response packet are passed in atpRspUData. The last packet of the transaction response is sent with the EOM flag set. Although you don’t provide a BDS, ATPResponse in fact creates one and calls the .ATP driver (as in an ATPSndRsp call). For this reason, the abRecord fields atpRspBDSPtr and atpNumBufs are used by ATPResponse; you should not expect these fields to remain unaltered during or after the function’s execution. During exactly-once transactions ATPResponse won’t complete until the release packet is received or the release timer expires. Warning: The maximum permissible size of the response message is 4624 bytes. Result codes noErr No error badATPSkt Bad responding socket noRelErr No release received atpLenErr Response too big sktClosed Socket closed by a cancel call noDataArea Too many outstanding ATP calls æKY ATPRspCancel æFp AppleTalk.p æT FUNCTION æD FUNCTION ATPRspCancel(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := ATPRspCancel(abRecord,async); æMM æRI II-296 æC Given the handle to the ABusRecord of a previously made ATPSndRsp or ATPResponse call, ATPRspCancel dequeues the ATPSndRsp or ATPResponse call, provided that the call hasn’t already completed. ATPRspCancel returns noErr if the ATPSndRsp or ATPResponse call is successfully removed from the queue. If it returns cbNotFound, check the abResult field of abRecord to verify that the ATPSndRsp or ATPResponse call has completed and determine its outcome. Result codes noErr No error cbNotFound ATP control block not found »Example This example shows the requesting side of an ATP transaction that asks for a 512-byte disk block from the responding end. The block number of the file is a byte and is contained in myBuffer[0]. VAR myABRecord: ABRecHandle; myBDSPtr: BDSPtr; myBuffer: PACKED ARRAY [0..511] OF CHAR; errCode: INTEGER; async: BOOLEAN; BEGIN errCode := ATPLoad; IF errCode <> noErr THEN WRITELN('Error in opening AppleTalk') {Maybe serial port B isn't available for use by AppleTalk} ELSE BEGIN {Prepare the BDS; allocate space for a one-element BDS} myBDSPtr := BDSPtr(NewPtr(SIZEOF(BDSElement))); WITH myBDSPtr^[0] DO BEGIN buffSize := 512; {size of our buffer used in reception} buffPtr := @myBuffer; {pointer to the buffer} END; {Prepare the ABusRecord} myBuffer[0] := CHR(1); {requesting disk block number 1} myABRecord := ABRecHandle(NewHandle(atpSize)); WITH myABRecord^^ DO BEGIN atpAddress.aNet := 0; atpAddress.aNode := 30; {we probably got this from an NBP call} atpAddress.aSocket := 15; {socket to send request to} atpReqCount := 1; {size of request data field (disk block #)} atpDataPtr := @myBuffer; {ptr to request to be sent} atpRspBDSPtr := @myBDSPtr; atpUserData := 0; {for your use} atpXO := FALSE; {at-least-once service} atpTimeOut := 5; {5-second timeout} atpRetries := 3; {3 retries; request will be sent 4 times max} atpNumBufs := 1; {we're only expecting 1 block to be returned} END; async := FALSE; {Send the request and wait for the response} errCode := ATPSndRequest(myABRecord, async); IF errCode <> noErr THEN WRITELN('An error occurred in the ATPSndRequest call') ELSE BEGIN {The disk block requested is now in myBuffer. We can verify } { that atpNumRsp contains 1, meaning one response received.} . . . END; END; END. æKY NBPRegister æFp AppleTalk.p æT FUNCTION æD FUNCTION NBPRegister(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := NBPRegister(abRecord,async); æMM æRT 20 æRI II-299, N20-2 æC ABusRecord <-- abOpcode {always tNBPRegister} <-- abResult {result code} --> abUserReference {for your use} --> nbpEntityPtr {pointer to entity name} --> nbpBufPtr {pointer to buffer} --> nbpBufSize {buffer size in bytes} --> nbpAddress.aSocket {socket address} --> nbpRetransmitInfo {retransmission information} NBPRegister adds the name and address of an entity to the node’s names table. NBPEntityPtr points to a variable of type EntityName containing the entity’s name. If the name is already registered, NBPRegister returns the result code nbpDuplicate. NBPAddress indicates the socket for which the name should be registered. NBPBufPtr and nbpBufSize specify the location and size of a buffer for NBP to use internally. While the variable of type EntityName is declared as three 32-byte strings, only the actual characters of the name are placed in the buffer pointed to by nbpBufPtr. For this reason, nbpBufSize needs only to be equal to the actual length of the name, plus an additional 12 bytes for use by NBP. Warning: This buffer must not be altered or released until the name is removed from the names table via an NBPRemove call. If you allocate the buffer through a NewHandle call, you must lock it as long as the name is registered. Warning: The zone field of the entity name must be set to the meta-character “*”. Result codes noErr No error nbpDuplicate Duplicate name already exists æKY NBPLookup æFp AppleTalk.p æT FUNCTION æD FUNCTION NBPLookup(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := NBPLookup(abRecord,async); æMM æRT 9, 20 æRI II-300, N9-1, 2, N20-2 æC ABusRecord <-- abOpcode {always tNBPLookup} <-- abResult {result code} --> abUserReference {for your use} --> nbpEntityPtr {pointer to entity name} --> nbpBufPtr {pointer to buffer} --> nbpBufSize {buffer size in bytes} <-> nbpDataField {number of addresses received} --> nbpRetransmitInfo {retransmission information} NBPLookup returns the addresses of all entities with a specified name. NBPEntityPtr points to a variable of type EntityName containing the name of the entity whose address should be returned. (Meta-characters are allowed in the entity name.) NBPBufPtr and nbpBufSize contain the location and size of an area of memory in which the entity names and their corresponding addresses should be returned. NBPDataField indicates the maximum number of matching names to find addresses for; the actual number of addresses found is returned in nbpDataField. NBPRetransmitInfo contains the retry interval and the retry count. When specifying nbpBufSize, for each NBP tuple expected, allow space for the actual characters of the name, the address, and four bytes for use by NBP. Result codes noErr No error nbpBuffOvr Buffer overflow æKY NBPExtract æFp AppleTalk.p æT FUNCTION æD FUNCTION NBPExtract(theBuffer: Ptr;numInBuf: INTEGER;whichOne: INTEGER; VAR abEntity: EntityName;VAR address: AddrBlock): OSErr; æDT myVariable := NBPExtract(theBuffer,numInBuf,whichOne,abEntity,address); æMM æRI II-300,V-515 æC This routine is provided in the alternate interface, but can be used as provided for extracting NBP entity names from a look-up response buffer. NBPExtract returns one address from the list of addresses returned by NBPLookup. TheBuffer and numInBuf indicate the location and number of tuples in the buffer. WhichOne specifies which one of the tuples in the buffer should be returned in the abEntity and address parameters. Result codes noErr No error extractErr Can’t find tuple in buffer æKY NBPConfirm æFp AppleTalk.p æT FUNCTION æD FUNCTION NBPConfirm(abRecord: ABRecHandle;async: BOOLEAN): OSErr; æDT myVariable := NBPConfirm(abRecord,async); æMM æRT 9 æRI II-301, N9-2 æC ABusRecord <-- abOpcode {always tNBPConfirm} <-- abResult {result code} --> abUserReference {for your use} --> nbpEntityPtr {pointer to entity name} <-- nbpDataField {socket number} --> nbpAddress {socket address} --> nbpRetransmitInfo {retransmission information} NBPConfirm confirms that an entity known by name and address still exists (is still entered in the names directory). NBPEntityPtr points to a variable of type EntityName that contains the name to confirm, and nbpAddress specifies the address to be confirmed. (No meta-characters are allowed in the entity name.) NBPRetransmitInfo contains the retry interval and the retry count. The socket number of the entity is returned in nbpDataField. NBPConfirm is more efficient than NBPLookup in terms of network traffic. Result codes noErr No error nbpConfDiff Name confirmed for different socket nbpNoConfirm Name not confirmed æKY NBPRemove æFp AppleTalk.p æT FUNCTION æD FUNCTION NBPRemove(abEntity: EntityPtr): OSErr; æDT myVariable := NBPRemove(abEntity); æMM æRI II-301 æC NBPRemove removes an entity name from the names table of the given entity’s node. Result codes noErr No error nbpNotFound Name not found æKY NBPLoad æFp AppleTalk.p æT FUNCTION æD FUNCTION NBPLoad: OSErr; æDT myVariable := NBPLoad; æMM æRI II-301 æC On a Macintosh 128K, NBPLoad reads the NBP code from the system resource file into the application heap. On a Macintosh 512K or XL, NBPLoad has no effect since the NBP code should have already been loaded when the .MPP driver was opened. Normally you’ll never need to call NBPLoad, because the AppleTalk Manager calls it when necessary. Result codes noErr No error æKY NBPUnload æFp AppleTalk.p æT FUNCTION æD FUNCTION NBPUnload: OSErr; æDT myVariable := NBPUnload; æMM æRI II-301 æC On a Macintosh 128K, NBPUnload makes the NBP code purgeable; the space isn’t actually released by the Memory Manager until necessary. On a Macintosh 512K or Macintosh XL, NBPUnload has no effect. Result codes noErr No error »Example This example of NBP registers our node as a print spooler, searches for any print spoolers registered on the network, and then extracts the information for the first one found. CONST mySocket = 20; VAR myABRecord: ABRecHandle; myEntity: EntityName; entityAddr: AddrBlock; nbpNamePtr: Ptr; myBuffer: PACKED ARRAY [0..999] OF CHAR; errCode: INTEGER; async: BOOLEAN; BEGIN errCode := MPPOpen; IF errCode <> noErr THEN WRITELN('Error in opening AppleTalk') {Maybe serial port B isn't available for use by AppleTalk} ELSE BEGIN {Call Memory Manager to allocate ABusRecord} myABRecord := ABRecHandle(NewHandle(nbpSize)); {Set up our entity name to register} WITH myEntity DO BEGIN objStr := 'Gene Station'; {we are called 'Gene Station' } typeStr := 'PrintSpooler'; { and are of type 'PrintSpooler'} zoneStr := '*'; {Allocate data space for the entity name (used by NBP)} nbpNamePtr := NewPtr(LENGTH(objStr) + LENGTH(typeStr) + LENGTH(zoneStr) + 12); END; {Set up the ABusRecord for the NBPRegister call} WITH myABRecord^^ DO BEGIN nbpEntityPtr := @myEntity; nbpBufPtr := nbpNamePtr; {buffer used by NBP internally} nbpBufSize := nbpNameBufSize; nbpAddress.aSocket := mySocket; {socket to register us on} nbpRetransmitInfo.retransInterval := 8; {retransmit every 64 } nbpRetransmitInfo.retransCount := 3; { ticks and try 3 times} END; async := FALSE; errCode := NBPRegister(myABRecord, async); IF errCode <> noErr THEN WRITELN('Error occurred in the NBPRegister call') {Maybe the name is already registered somewhere else on the } { network.} ELSE BEGIN {Now that we've registered our name, find others of type } { 'PrintSpooler'.} WITH myEntity DO BEGIN objStr := '='; {any one of type } typeStr := 'PrintSpooler'; { “PrintSpooler” } zoneStr := '*'; { in our zone} END; WITH myABRecord^^ DO BEGIN nbpEntityPtr := @myEntity; nbpBufPtr := @myBuffer; {buffer to place responses in} nbpBufSize := SIZEOF(myBuffer); {The field nbpDataField, before the NBPLookup call, represents an } { approximate number of responses. After the call, nbpDataField } { contains the actual number of responses received.} nbpDataField := 100; {we want about 100 responses back} END; errCode := NBPLookup(myABRecord, async); {make sync call} IF errCode <> noErr THEN WRITELN('An error occurred in the NBPLookup') {Did the buffer overflow?} ELSE BEGIN {Get the first reply} errCode := NBPExtract(@mybuffer, myABRecord^^.nbpDataField, 1, myEntity, entityAddr); {The socket address and name of the entity are returned here. If we } { want all of them, we'll have to loop for each one in the buffer.} IF errCode <> noErr THEN WRITELN('Error in NBPExtract'); {Maybe the one we wanted wasn't in the buffer} END; END; END; END. æKY RemoveHdlBlocks æFp AppleTalk.p æT PROCEDURE æD PROCEDURE RemoveHdlBlocks; { RemoveHdlBlks is a routine that is called automatically at the beginning of every pascal call. It checks for free (disposable) memory blocks that the interface has allocated, and disposes of them. The memory blocks have been allocated by the NewHandle call.Most of these memory blocks are small (on the order of 20-50 bytes). The user, at his option, may also make the call whenever s/he wants to.The general rule is that one memory block will be allocated every time a network call is made; and it will not be free until the call completes. } æDT RemoveHdlBlocks; æC æKY GetNodeAddress æFp AppleTalk.p æT FUNCTION æD FUNCTION GetNodeAddress(VAR myNode: INTEGER;VAR myNet: INTEGER): OSErr; æDT myVariable := GetNodeAddress(myNode,myNet); æRI II-303 æC GetNodeAddress returns the current node ID and network number of the caller. If the .MPP driver isn’t installed, it returns noMPPErr. If myNet contains 0, this means that a bridge hasn’t yet been found. Result codes noErr No error noMPPErr MPP driver not installed æKY IsMPPOpen æFp AppleTalk.p æT FUNCTION æD FUNCTION IsMPPOpen: BOOLEAN; æDT myVariable := IsMPPOpen; æRI II-304 æC [Not in ROM] IsMPPOpen returns TRUE if the .MPP driver is loaded and running. æKY IsATPOpen æFp AppleTalk.p æT FUNCTION æD FUNCTION IsATPOpen: BOOLEAN; { IsATPOpen : BOOLEAN; [Not in ROM] IsATPOpen returns TRUE if the .ATP driver is loaded and running. } æDT myVariable := IsATPOpen; æRI II-304 æC [Not in ROM] IsATPOpen returns TRUE if the .ATP driver is loaded and running. æKY Balloons.p æKL HMBalloonRect HMBaloonPict HMExtractHelpMsg HMFillCitationString HMGetBalloons HMGetDialogResID HMGetFont HMGetFontSize HMGetMenuResID HMIsBalloon HMMouseInApplRgn HMRemoveBalloon HMScanTemplateItems HMSetBalloons HMSetDialogResID HMSetFont HMSetFontSize HMSetMenuResID HMShowBalloon HMShowMenuBalloon HMState hdlgLocalCoords hdlgSaveBits hdlgUseSubID helpItem hmBadSelector hmBalloonAborted HMCompareItem hmCouldNotLoadPackage HMDefaultRecord HMDefaultRecPtr hmGestaltBalloonsOff hmGestaltBalloonsOn hmGestaltHelpType hmHelpDisabled HMLHHandleType hmMemFullErr HMMessageRecord HMMessageRecordPtr HMNamedResourceItem HMPicHDefaultRecord HMPicHDefaultRecPtr HMPicHMsgRecord HMPicHMsgRecPtr HMPictDefaultRecord HMPictDefaultRecPtr HMPictItem HMPictMsgRecord HMPictMsgRecPtr hmResNotFound hmSameAsLastBalloon HMSkipItem hmSkippedBalloon HMSTHandleType HMStringDefaultRecord HMStringDefaultRecPtr HMStringItem HMStringMsgRecord HMStringMsgRecPtr HMStringRecord HMStringResItem HMStringResType HMStrResDefaultRecord HMStrResDefaultRecPtr HMSTRResItem HMStrResMsgRecord HMStrResMsgRecPtr HMTEHDefaultRecord HMTEHDefaultRecPtr HMTEHMsgRecord HMTEHMsgRecPtr HMTEResItem HMTEResType HMTEStyleType HMTrackCntlItem hmUnknownHelpType HMVersionWord hmWrongVersion hwinUseResID hwinUseSubID kBalloonWDEFID kHMAboutHelpID kHMChecked kHMCheckedItem kHMDisabled kHMDisabledItem kHMEasy1Access kHMEasy2Access kHMEasy3Access kHMEnabled kHMEnabledItem kHMHelpIconOff kHMHelpIconOn kHMHelpID kHMHelpMenuID kHMhrctAbsolute kHMInDisabledScrollBar kHMInDragIndex kHMInGoAwayIndex kHMInGrowIndex kHMInScrollBar kHMInZoomIndex kHMMenuTitleIndex khmmPict khmmPictHandle khmmString khmmStringRes khmmSTRRes khmmTEHandle khmmTERes kHMMultiFinderIndex kHMOther kHMOtherItem kHMUsingHelpIndex kHMUsingHelpItem kHMWhatIsIndex kHMWhatIsItem RectPtr æKY HMVersionWord æFp Balloons.p æT CONST æD HMVersionWord = $0002; æC æKY hmHelpDisabled æFp Balloons.p æT CONST æD { Help Mgr error range: -850 to -874 } hmHelpDisabled = -850; æC æKY hmResNotFound æFp Balloons.p æT CONST æD hmResNotFound = -851; æC æKY hmMemFullErr æFp Balloons.p æT CONST æD hmMemFullErr = -852; æC æKY hmBalloonAborted æFp Balloons.p æT CONST æD hmBalloonAborted = -853; æC æKY hmSameAsLastBalloon æFp Balloons.p æT CONST æD hmSameAsLastBalloon = -854; æC æKY hmBadSelector æFp Balloons.p æT CONST æD hmBadSelector = -856; æC æKY hmSkippedBalloon æFp Balloons.p æT CONST æD hmSkippedBalloon = -857; æC æKY hmWrongVersion æFp Balloons.p æT CONST æD hmWrongVersion = -858; æC æKY hmUnknownHelpType æFp Balloons.p æT CONST æD hmUnknownHelpType = -859; æC æKY hmCouldNotLoadPackage æFp Balloons.p æT CONST æD hmCouldNotLoadPackage = -860; æC æKY hmGestaltHelpType æFp Balloons.p æT CONST æD { Gestalt } hmGestaltHelpType = 'help'; æC æKY hmGestaltBalloonsOn æFp Balloons.p æT CONST æD hmGestaltBalloonsOn = 0; æC æKY hmGestaltBalloonsOff æFp Balloons.p æT CONST æD hmGestaltBalloonsOff = 1; æC æKY kHMUsingHelpItem æFp Balloons.p æT CONST æD kHMUsingHelpItem = 1; æC æKY kHMWhatIsItem æFp Balloons.p æT CONST æD kHMWhatIsItem = 3; æC æKY kHMHelpID æFp Balloons.p æT CONST æD kHMHelpID = -5696; æC æKY kHMMultiFinderIndex æFp Balloons.p æT CONST æD { System STR# resource indexes } kHMMultiFinderIndex = 1; æC æKY kHMMenuTitleIndex æFp Balloons.p æT CONST æD kHMMenuTitleIndex = 2; æC æKY kHMUsingHelpIndex æFp Balloons.p æT CONST æD kHMUsingHelpIndex = 3; æC æKY kHMWhatIsIndex æFp Balloons.p æT CONST æD kHMWhatIsIndex = 4; æC æKY kHMInDragIndex æFp Balloons.p æT CONST æD kHMInDragIndex = 5; æC æKY kHMInGrowIndex æFp Balloons.p æT CONST æD kHMInGrowIndex = 6; æC æKY kHMInGoAwayIndex æFp Balloons.p æT CONST æD kHMInGoAwayIndex = 7; æC æKY kHMInZoomIndex æFp Balloons.p æT CONST æD kHMInZoomIndex = 8; æC æKY kHMInScrollBar æFp Balloons.p æT CONST æD kHMInScrollBar = 9; æC æKY kHMInDisabledScrollBar æFp Balloons.p æT CONST æD kHMInDisabledScrollBar = 10; æC æKY kHMEasy1Access æFp Balloons.p æT CONST æD kHMEasy1Access = 11; æC æKY kHMEasy2Access æFp Balloons.p æT CONST æD kHMEasy2Access = 12; æC æKY kHMEasy3Access æFp Balloons.p æT CONST æD kHMEasy3Access = 13; æC æKY kHMAboutHelpID æFp Balloons.p æT CONST æD { misc Constants } kHMAboutHelpID = -5696; æC æKY kHMHelpMenuID æFp Balloons.p æT CONST æD kHMHelpMenuID = -5696; æC æKY kHMHelpIconOn æFp Balloons.p æT CONST æD kHMHelpIconOn = -5696; æC æKY kHMHelpIconOff æFp Balloons.p æT CONST æD kHMHelpIconOff = -5695; æC æKY kBalloonWDEFID æFp Balloons.p æT CONST æD { WhatIs default WDEF res ID } kBalloonWDEFID = 126; æC æKY helpItem æFp Balloons.p æT CONST æD { Dialog item template type } helpItem = 1; æC æKY kHMhrctAbsolute æFp Balloons.p æT CONST æD { hrct Options } kHMhrctAbsolute = 0; æC æKY kHMEnabledItem æFp Balloons.p æT CONST æD { Generic defines for the switch items used in 'hmnu' & 'hdlg' } kHMEnabledItem = 0; æC æKY kHMDisabledItem æFp Balloons.p æT CONST æD kHMDisabledItem = 1; æC æKY kHMCheckedItem æFp Balloons.p æT CONST æD kHMCheckedItem = 2; æC æKY kHMOtherItem æFp Balloons.p æT CONST æD kHMOtherItem = 3; æC æKY hdlgUseSubID æFp Balloons.p æT CONST æD hdlgUseSubID = 0; { if set then use sub ID's to fine res ID} æC æKY hdlgLocalCoords æFp Balloons.p æT CONST æD hdlgLocalCoords = 1; { if set then use hdlg rects as local coords, ignoring item rects} æC æKY hdlgSaveBits æFp Balloons.p æT CONST æD hdlgSaveBits = 2; { if set then use save bits behind balloon} æC æKY hwinUseResID æFp Balloons.p æT CONST æD { Option bits for hwin resources } hwinUseResID = 0; æC æKY hwinUseSubID æFp Balloons.p æT CONST æD hwinUseSubID = 1; æC æKY HMStringItem æFp Balloons.p æT CONST æD { Constants for Help Types in 'hmnu', 'hdlg', 'hrct' resources } HMStringItem = 1; æC æKY HMPictItem æFp Balloons.p æT CONST æD HMPictItem = 2; æC æKY HMStringResItem æFp Balloons.p æT CONST æD HMStringResItem = 3; æC æKY HMTEResItem æFp Balloons.p æT CONST æD HMTEResItem = 6; æC æKY HMSTRResItem æFp Balloons.p æT CONST æD HMSTRResItem = 7; æC æKY HMSkipItem æFp Balloons.p æT CONST æD HMSkipItem = 256; æC æKY HMCompareItem æFp Balloons.p æT CONST æD HMCompareItem = 512; æC æKY HMNamedResourceItem æFp Balloons.p æT CONST æD HMNamedResourceItem = 1024; æC æKY HMTrackCntlItem æFp Balloons.p æT CONST æD HMTrackCntlItem = 2048; æC æKY khmmString æFp Balloons.p æT CONST æD { Constants for hmmHelpType's when filling out HMMessageRecord } khmmString = 1; æC æKY khmmPict æFp Balloons.p æT CONST æD khmmPict = 2; æC æKY khmmStringRes æFp Balloons.p æT CONST æD khmmStringRes = 3; æC æKY khmmTEHandle æFp Balloons.p æT CONST æD khmmTEHandle = 4; æC æKY khmmPictHandle æFp Balloons.p æT CONST æD khmmPictHandle = 5; æC æKY khmmTERes æFp Balloons.p æT CONST æD khmmTERes = 6; æC æKY khmmSTRRes æFp Balloons.p æT CONST æD khmmSTRRes = 7; æC æKY kHMEnabled æFp Balloons.p æT CONST æD kHMEnabled = 1; æC æKY kHMDisabled æFp Balloons.p æT CONST æD kHMDisabled = 2; æC æKY kHMChecked æFp Balloons.p æT CONST æD kHMChecked = 4; æC æKY kHMOther æFp Balloons.p æT CONST æD kHMOther = 8; æC æKY HMTEResType æFp Balloons.p æT CONST æD { ResTypes for Styled TE Handles when extracting from Resources } HMTEResType = 'thdl'; æC æKY HMTEStyleType æFp Balloons.p æT CONST æD HMTEStyleType = 'tsty'; æC æKY HMSTHandleType æFp Balloons.p æT CONST æD HMSTHandleType = 'tstb'; æC æKY HMLHHandleType æFp Balloons.p æT CONST æD HMLHHandleType = 'thtb'; æC æKY RectPtr æFp Balloons.p æT RECORD æD RectPtr = ^Rect; æC æKY HMStringResType æFp Balloons.p æT RECORD æD HMStringResType = PACKED RECORD hmmResID: INTEGER; hmmIndex: INTEGER; END; æC æKY HMStringMsgRecord HMStringMsgRecPtr æFp Balloons.p æT RECORD æD HMStringMsgRecPtr = ^HMStringMsgRecord; HMStringMsgRecord = RECORD hmmHelpType: INTEGER; hmmString: Str255; END; æC æKY HMPictMsgRecord HMPictMsgRecPtr æFp Balloons.p æT RECORD æD HMPictMsgRecPtr = ^HMPictMsgRecord; HMPictMsgRecord = RECORD hmmHelpType: INTEGER; hmmPict: INTEGER; fill: ARRAY [0..253] OF Byte; END; æC æKY HMTEHMsgRecord HMTEHMsgRecPtr æFp Balloons.p æT RECORD æD HMTEHMsgRecPtr = ^HMTEHMsgRecord; HMTEHMsgRecord = RECORD hmmHelpType: INTEGER; hmmTEHandle: Handle; fill: ARRAY [0..251] OF Byte; END; æC æKY HMStrResMsgRecord HMStrResMsgRecPtr æFp Balloons.p æT RECORD æD HMStrResMsgRecPtr = ^HMStrResMsgRecord; HMStrResMsgRecord = RECORD hmmHelpType: INTEGER; hmmStrRes: HMStrResType; fill: ARRAY [0..249] OF Byte; END; æC æKY HMPicHMsgRecord HMPicHMsgRecPtr æFp Balloons.p æT RECORD æD HMPicHMsgRecPtr = ^HMPicHMsgRecord; HMPicHMsgRecord = RECORD hmmHelpType: INTEGER; hmmPicHandle: PicHandle; fill: ARRAY [0..251] OF Byte; END; æC æKY HMDefaultRecord HMDefaultRecPtr æFp Balloons.p æT RECORD æD HMDefaultRecPtr = ^HMDefaultRecord; HMDefaultRecord = RECORD hmVersion: INTEGER; hmDefMessage: HMStringMsgRecord; hmHelpVRefNum: INTEGER; hmHelpDirID: LONGINT; hmSearchAlternateFiles: BOOLEAN; END; æC æKY HMStringDefaultRecord HMStringDefaultRecPtr æFp Balloons.p æT RECORD æD HMStringDefaultRecPtr = ^HMStringDefaultRecord; HMStringDefaultRecord = RECORD hmVersion: INTEGER; hmDefMessage: HMStringMsgRecord; hmHelpVRefNum: INTEGER; hmHelpDirID: LONGINT; hmSearchAlternateFiles: BOOLEAN; END; æC æKY HMPictDefaultRecord HMPictDefaultRecPtr æFp Balloons.p æT RECORD æD HMPictDefaultRecPtr = ^HMPictDefaultRecord; HMPictDefaultRecord = RECORD hmVersion: INTEGER; hmDefMessage: HMPictMsgRecord; hmHelpVRefNum: INTEGER; hmHelpDirID: LONGINT; hmSearchAlternateFiles: BOOLEAN; END; æC æKY HMTEHDefaultRecord HMTEHDefaultRecPtr æFp Balloons.p æT RECORD æD HMTEHDefaultRecPtr = ^HMTEHDefaultRecord; HMTEHDefaultRecord = RECORD hmVersion: INTEGER; hmDefMessage: HMTEHMsgRecord; hmHelpVRefNum: INTEGER; hmHelpDirID: LONGINT; hmSearchAlternateFiles: BOOLEAN; END; æC æKY HMStrResDefaultRecord HMStrResDefaultRecPtr æFp Balloons.p æT RECORD æD HMStrResDefaultRecPtr = ^HMStrResDefaultRecord; HMStrResDefaultRecord = RECORD hmVersion: INTEGER; hmDefMessage: HMStrResMsgRecord; hmHelpVRefNum: INTEGER; hmHelpDirID: LONGINT; hmSearchAlternateFiles: BOOLEAN; END; æC æKY HMPicHDefaultRecord HMPicHDefaultRecPtr æFp Balloons.p æT RECORD æD HMPicHDefaultRecPtr = ^HMPicHDefaultRecord; HMPicHDefaultRecord = RECORD hmVersion: INTEGER; hmDefMessage: HMPicHMsgRecord; hmHelpVRefNum: INTEGER; hmHelpDirID: LONGINT; hmSearchAlternateFiles: BOOLEAN; END; æC æKY HMStringRecord æFp Balloons.p æT RECORD æD HMStringRecord = RECORD hmmHelpType: INTEGER; hmmFont: INTEGER; hmmFontSize: INTEGER; hmmMessage: ARRAY [0..255] OF Byte; END; æC æKY HMMessageRecord HMMessageRecordPtr æFp Balloons.p æT RECORD æD HMMessageRecordPtr = ^HMMessageRecord; HMMessageRecord = RECORD hmmHelpType: Integer; CASE Integer OF khmmString: (hmmString: Str255; ); khmmPict: (hmmPict: Integer; ); khmmStringRes: (hmmStringRes: HMStringResType; ); khmmTEHandle: (hmmTRHandle: TEHandle; ); khmmPictHandle: (hmmPictHandle: PicHandle; ); khmmTERes: (hmmTERes: Integer; ); khmmSTRRes: (hmmSTRRes: Integer; ); END; æC æKY HMState æFp Balloons.p æT FUNCTION æD FUNCTION HMState(VAR state: HMStateRecord): OSErr; INLINE $303C,$0200,_Pack14; æDT myVariable := HMState(state); æC æKY HMShowBalloon æFp Balloons.p æT FUNCTION æD FUNCTION HMShowBalloon(aHelpMsg: HMMessageRecord;tip: Point;VAR alternateRect: Rect; tipProc: Ptr;theProc: INTEGER;variant: INTEGER;saveBits: BOOLEAN): INTEGER; INLINE $303C,$0B01,_Pack14; æDT myVariable := HMShowBalloon(aHelpMsg,tip,alternateRect,tipProc,theProc,variant,saveBits); æC If help is enabled, you can use the HMShowBalloon function to display a balloon containing the message specified by the message parameter; the balloon’s tip is located at the point specified by the tip parameter. Use the HMShowBalloon function to display a help message for an item that the user can move. Use the HMShowMenuBalloon function to display help messages for your application’s non-standard menus. Parameter Description message specifies the help message to be displayed. The HMMessageRecord data type is described in “The Help Message Record” earlier in this chapter. tip specifies, in global coordinates, the point where you want to position the balloon’s tip. For additional information about how the Help Manager positions balloons, see “How the Help Manager Positions the Help Balloon” earlier in this chapter. hotRect defines the area for which a specific help message is owned. That is, if the user moves the cursor anywhere outside the area specified by the hotRect parameter (once a balloon has been displayed), the Help Manager will remove the balloon This area is also the area of drift for the balloon tip. That is, if your specification for the tip parameter would force the Help Manager to position a balloon so that it obscures the element to be explained or so that it spills off the screen, the Help Manager attempts to relocate the tip within the area defined by the hotRect parameter. See “How the Help Manager Positions the Help Balloon” earlier in this chapter for additional information. tipProc specifies the address of a procedure you write that tests the values of the tip position and the balloon rectangle calculated by the Help Manager. You would write such a procedure if you anticipated problems positioning a help balloon. Using this function gives the application one more chance to modify the balloon’s position or dimensions before displaying it. Pass NIL for the tipProc parameter if you want the Help Manager to ignore the HMBaloonHook function. For additional information, see “Testing the Tip Position and the Dimensions of the Help Balloon” earlier in this chapter for additional information. theProc specifies the resource ID of the window definition procedure that you want the Help Manager to use to define the help balloon shape. The Help Manager reads the ‘WDEF’ resource into memory if it’s not already in memory. If the Help Manager cannot find or read the resource, the balloon is not displayed and the function returns the system error -192, resNotFound. To use the Help Manager’s default balloon shape, pass 0 for both the procedure and the variant parameter. variant specifies the variation code for the window definition procedure specified by the parameter theProc. If you specify 0 for the parameter theProc, you can still specify a value for variant to indicate a preferred tip position for the default balloon. See "Defining Your Own Balloon Shape" earlier in this chapter for additional information. saveBits a value of TRUE specifies that the Help Manager should save the bits behind the balloon. Only use the saveBits option if you are certain that the bits behind the balloon will still be valid when the balloon is removed; as would be the case, for example, with the bits behind a pulled down menu. A value of FALSE specifies that the Window Manager should generate an update event for the window behind the balloon when you remove the balloon. You must specify FALSE for saveBits if the parameter theProc is non-zero,that is, if you are defining your own balloon shape. The HMShowBalloon function returns the noErr result if the Help Manager displays a balloon. If help was disabled or if no balloon was displayed, the function returns a non-zero result. Result codes noErr 0 No error paramErr –50 Bad parameters passed in message record memFullErr –108 Not enough room in heap zone resNotFound –192 The balloon ‘WDEF’ could not be read hmHelpDisabled –850 Help is disabled hmBalloonAborted –853 Cursor was not stationary hmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call æKY HMRemoveBalloon æFp Balloons.p æT FUNCTION æD FUNCTION HMRemoveBalloon: INTEGER; INLINE $303C,$0002,_Pack14; æDT myVariable := HMRemoveBalloon(paramList); æC FUNCTION HMRemoveBalloon : OSErr; The HMRemoveBalloon function removes any help message that is currently visible. If no help message is visible, the HMRemoveBalloon function does nothing. Use the HMRemoveBalloon function to remove balloons created either by HMShowBalloon or HMShowMenuBalloon. If a balloon is visible and the user disables help, the Help Manager calls this function automatically. The Help Manager also calls the HMRemoveBalloon function so that no more than one help balloon is displayed at any time. Thus if your application makes successive calls to show balloons without calling the HMRemoveBalloon function, the Help Manager calls the HMRemoveBalloon function automatically to remove the first balloon before displaying the second balloon. If your application has called the HMShowBalloon function to display a help message and the hotRect parameter was NIL, call the HMRemoveBalloon function when the cursor moves out of the specified area. In a customized 'MDEF' definition procedure, call the HMRemoveBalloon function before hiding a drawn menu. In a customized 'MBDF' procedure, call the HMRemoveBalloon function in response to the messages SaveBits and RestoreBits before saving or restoring any bits. Results codes noErr 0 No error; a balloon was removed paramErr –50 Bad parameters passed in message record hmHelpDisabled –850 Balloon help is disabled hmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call æKY HMGetBalloons æFp Balloons.p æT FUNCTION æD FUNCTION HMGetBalloons: BOOLEAN; INLINE $303C,$0003,_Pack14; æDT myVariable := HMGetBalloons(paramList); æC The HMGetBalloons function returns the current setting of the flag parameter for the HMSetBalloons function. æKY HMSetBalloons æFp Balloons.p æT FUNCTION æD FUNCTION HMSetBalloons(flag: BOOLEAN): INTEGER; INLINE $303C,$0104,_Pack14; æDT myVariable := HMSetBalloons(flag); æC The following routine allows you to set a flag that activates balloon help, find out the current setting of this flag, and determine whether a help balloon is being displayed on the screen. FUNCTION HMSetBalloons (flag: Boolean) : OSErr; Calling the HMSetBalloons function activates the Help Manager if the value of the flag parameter is TRUE and turns it off if the value of flag is FALSE. When help is enabled, the Help Manager automatically displays balloons for standard window parts and system dialog boxes. Disabling help removes any balloon displayed by calls to the HMShowBalloon or HMShowMenuBalloon functions. Result codes noErr 0 No error hmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call æKY HMShowMenuBalloon æFp Balloons.p æT FUNCTION æD FUNCTION HMShowMenuBalloon(itemNum: INTEGER;itemMenuID: INTEGER;itemFlags: LONGINT; itemReserved: LONGINT;tip: Point;alternateRect: Ptr;tipProc: Ptr;theProc: INTEGER; variant: INTEGER): INTEGER; INLINE $303C,$0E05,_Pack14; æDT myVariable := HMShowMenuBalloon(itemNum,itemMenuID,itemFlags,itemReserved,tip,alternateRect,tipProc,theProc,variant); æC FUNCTION HMShowMenuBalloon (itemNum: Integer; itemMenuID: Integer; itemFlags: LongInt; itemReserved: LongInt; tip: Point; hotRect: rectPtr; tipProc: Ptr; reserved, reserved: Integer) : OSErr; The HMShowMenuBalloon function allows you to display help balloons for an application's non-standard menu. You call the HMShowMenuBalloon function from a menu’s ‘MDEF’ definition procedure right after drawing, highlighting, or determining that the cursor is over a menu item. Parameter Description itemNum specifies the number of the menu item to which the cursor is pointing. If the cursor points to the menu title, the itemNum parameter contains 0;if the cursor points to a dashed line, the itemNum parameter contains -1. itemMenuID specifies the menuID of the menu currently in use. itemFlags specifies the menu's enabledFlags Longword, which tells the Help Manager whether the menu item is enabled or disabled. The Help Manager uses this value to select the corresponding message from the ‘hmnu’ resource associated with the menu specified by itemMenuID. itemReserved reserved for future expansion; specify 0 tip specifies, in global coordinates, the point where you want the balloon’s tip. For additional information about how the Help Manager positions balloons, see “How the Help Manager Positions the Help Balloon” earlier in this chapter. hotRect specifies the area of drift for the balloon tip. That is, if your specification for the tip parameter would force the Help Manager to position a balloon so that it obscures the element to be explained or so that it spills off the screen, the Help Manager attempts to relocate the tip within the area defined by the hotRect.parameter. See “How the Help Manager Positions the Help Balloon” earlier in this chapter for additional information. tipProc specifies the address of a procedure you write that tests the values of the tip position and the balloon rectangle calculated by the Help Manager. You would write such a procedure if you anticipated problems positioning a help balloon. Using this function gives the application one more chance to modify the balloon’s position or the dimensions of the balloon before displaying it. Pass NIL for the tipProc parameter if you want the Help Manager to ignore the HMBaloonHook function. For additional information, see “Changing the Tip Position and the Dimensions of the Help Balloon” earlier in this chapter for additional information. reserved specify 0. reserved specify 0. Result codes noErr 0 No error paramErr –50 Bad parameters passed in message record memFullErr –108 Not enough room in heap zone resNotFound –192 'hmnu' resource could not be read hmHelpDisabled –850 Balloon help is disabled hmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call æKY HMMouseInApplRgn æFp Balloons.p æT FUNCTION æD FUNCTION HMMouseInApplRgn: BOOLEAN; INLINE $303C,$0006,_Pack14; æDT myVariable := HMMouseInApplRgn(paramList); æC æKY HMIsBalloon æFp Balloons.p æT FUNCTION æD FUNCTION HMIsBalloon: BOOLEAN; INLINE $303C,$0007,_Pack14; æDT myVariable := HMIsBalloon(paramList); æC The HMIsBalloon function determines whether a help balloon is currently showing. A return value of TRUE means that a balloon is showing; a value of FALSE means that no balloon is showing. æKY HMSetFont æFp Balloons.p æT FUNCTION æD FUNCTION HMSetFont(font: INTEGER): INTEGER; INLINE $303C,$0108,_Pack14; æDT myVariable := HMSetFont(font); æC æKY HMSetFontSize æFp Balloons.p æT FUNCTION æD FUNCTION HMSetFontSize(fontsize: INTEGER): INTEGER; INLINE $303C,$0109,_Pack14; æDT myVariable := HMSetFontSize(fontsize); æC æKY HMGetFont æFp Balloons.p æT FUNCTION æD FUNCTION HMGetFont(VAR font: INTEGER): INTEGER; INLINE $303C,$020A,_Pack14; æDT myVariable := HMGetFont(font); æC æKY HMGetFontSize æFp Balloons.p æT FUNCTION æD FUNCTION HMGetFontSize(VAR fontSize: INTEGER): INTEGER; INLINE $303C,$020B,_Pack14; æDT myVariable := HMGetFontSize(fontSize); æC æKY HMSetDialogResID æFp Balloons.p æT FUNCTION æD FUNCTION HMSetDialogResID(resID: INTEGER): INTEGER; INLINE $303C,$010C,_Pack14; æDT myVariable := HMSetDialogResID(resID); æC æKY HMSetMenuResID æFp Balloons.p æT FUNCTION æD FUNCTION HMSetMenuResID(menuID: INTEGER;resID: INTEGER): INTEGER; INLINE $303C,$020D,_Pack14; æDT myVariable := HMSetMenuResID(menuID,resID); æC æKY HMBalloonRect æFp Balloons.p æT FUNCTION æD FUNCTION HMBalloonRect(aHelpMsg: struct HMMessageRecord;VAR coolRect: Rect): INTEGER; INLINE $303C,$040E,_Pack14; æDT myVariable := HMBalloonRect(aHelpMsg,coolRect); æC The HMBalloonRect procedure calculates the dimensions of a balloon containing a specified message. You can use the results of this procedure to provide the dimensions of a customized balloon that you define yourself. The HMBalloonRect function returns a rectangle in the coolRect parameter that is just the right size to display the text message specified by the aHelpMessage parameter. See “Providing Help for Application-Specific Elements” earlier in this chapter for a description of the HMMessageRecord data type. Result codes noErr 0 No Error paramErr –50 Bad parameters passed in message memFullErr –108 Not enough room in heap zone recordhmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call æKY HMBaloonPict æFp Balloons.p æT FUNCTION æD FUNCTION HMBaloonPict(aHelpMsg: struct HMMessageRecord;VAR coolPict: Handle): INTEGER; INLINE $303C,$040F,_Pack14; æDT myVariable := HMBaloonPict(aHelpMsg,coolPict); æC The HMBalloonPict function returns a handle to a picture that shows how the text contained in aHelpMessage is going to be displayed. Result codes noErr 0 No Error paramErr –50 Bad parameters passed in message memFullErr –108 Not enough room in heap zone hmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call æKY HMScanTemplateItems æFp Balloons.p æT FUNCTION æD FUNCTION HMScanTemplateItems(whichID: INTEGER;whichResFile: INTEGER;whichType: ResType): INTEGER; INLINE $303C,$0410,_Pack14; æDT myVariable := HMScanTemplateItems(whichID,whichResFile,whichType); æC You use this function when you have no other way of associating a dialog box or window with an 'hdlg' or 'hrct' resource. This might happen because you have a dialog box with a changing title and a fixed item list or because you want to supply help for areas of a window whose title changes. When you call this function the Help Manager will provide help messages (for the frontmost window) from the resource whose type you specify with the whichType parameter and whose ID you specify using the which ID parameter. The resource must reside in the file specified by the whichResFile parameter and this file must be open. The whichType parameter specifies the type of the resource and must be either 'hdlg' or 'hrct'. Result codes noErr 0 No error fnOpenErr –38 Resource file was not open paramErr –50 Bad parameters passed in message record memFullErr –108 Not enough room in heap zone resnotFound –192 'hmnu' resource could not be read hmHelpDisabled –850 Balloon help is disabled hmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call æKY HMExtractHelpMsg æFp Balloons.p æT FUNCTION æD FUNCTION HMExtractHelpMsg(whichType: ResType;whichResID: INTEGER;whichMsg: INTEGER; whichState: INTEGER;VAR aHelpMsg: HMMessageRecord): INTEGER; INLINE $303C,$0711,_Pack14; æDT myVariable := HMExtractHelpMsg(whichType,whichResID,whichMsg,whichState,aHelpMsg); æC æKY HMFillCitationString æFp Balloons.p æT FUNCTION æD FUNCTION HMFillCitationString(origString: StringPtr;stuffString: StringPtr; key: INTEGER): INTEGER; INLINE $303C,$0512,_Pack14; æDT myVariable := HMFillCitationString(origString,stuffString,key); æC æKY HMGetDialogResID æFp Balloons.p æT FUNCTION æD FUNCTION HMGetDialogResID(VAR resID: INTEGER): INTEGER; INLINE $303C,$0213,_Pack14; æDT myVariable := HMGetDialogResID(resID); æC The following routines allow you to override the 'hdlg' or 'hmnu' resources that the Help Manager currently associates with your menus and dialog boxes. FUNCTION HMGetDialogResID (VAR resID : Integer) : OSErr; The HMGetDialogResID function returns the 'hdlg' resource ID that the Help Manager is currently using to provide help messages for a dialog box. If there is no current resource, resID contains -1. Result codes noErr 0 No error memFullErr –108 Not enough room in the heap zone resNotFound –192 'hdlg' resource could not be read hmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call FUNCTION HMSetDialogResID (resID: Integer) : OSErr; You can use the HMSetDialogResID function in two ways: 1. If a dialog or alert item list ('DITL') does not include a helpItem specifying an 'hdlg' ID that the Help Manager should use to display help messages, calling the HMSetDialogResID function just before displaying the dialog or alert box tells the Help Manager to display help messages stored in the 'hdlg' resource whose ID is specified by resID. 2. If a dialog or alert item list does include a helpItem, you call the HMSetDialogResID function just before displaying the dialog or alert box to override the 'hdlg' ID resource specified in the helpItem field. Call the HMSetDialogResID function with a resID value of -1 after displaying the alert or dialog box to clear (reset) the first call. Result codes noErr 0 No error memFullErr –108 Not enough room in the heap zone resNotFound –192 'hdlg' resource could not be read hmCouldnotLoadPackage –860 There was not enough memory to load pacage hmOperationUnsupported –861 Could not interpret call æKY HMGetMenuResID æFp Balloons.p æT FUNCTION æD FUNCTION HMGetMenuResID(menuID: INTEGER;VAR resID: INTEGER): INTEGER; INLINE $303C,$0314,_Pack14; æDT myVariable := HMGetMenuResID(menuID,resID); æC The HMSetMenuResID function overrides the ‘hmnu’ resource ID used to provide help text for a particular menu. The menuID parameter specifies an existing menu ID in the application’s menu list. The resID parameter specifies a ‘hmnu’ resource ID that is to be used in place of the ‘hmnu’ resource normally used to provide help for the specified menu. If the menuID is not in the menu list, the function does nothing. To dissociate the menu specified by menuID from the resource specified by resID, specify -1 for the resID parameter. Result codes noErr 0 No error memFullErr –108 Not enough room in the heap zone resNotFound –192 'hdlg' resource could not be read hmCouldnotLoadPackage –860 There was not enough memory to load package hmOperationUnsupported –861 Could not interpret call æKY Controls.p æKL DisposeControl DragControl Draw1Control DrawControls FindControl GetAuxCtl GetCRefCon GetCTitle GetCtlAction GetCtlMax GetCtlMin GetCtlValue GetCVariant GetNewControl HideControl HiliteControl KillControls MoveControl NewControl SetCRefCon SetCTitle SetCtlAction SetCtlColor SetCtlMax SetCtlMin SetCtlValue ShowControl SizeControl TestControl TrackControl UpdtControl autoTrack AuxCtlHandle AuxCtlPtr AuxCtlRec calcCntlRgn calcCRgns calcThumbRgn cBodyColor CCTabHandle CCTabPtr cFrameColor checkBoxProc ControlHandle ControlPtr ControlRecord cTextColor cThumbColor CtlCTab dispCntl dragCntl drawCntl hAxisOnly inButton inCheckBox inDownButton initCntl inLabel inMenu inPageDown inPageUp inThumb inTriangle inUpButton noConstraint popupMenuProc popupTitleCenterJust popupTitleLeftJust popupTitleRightJust posCntl pushButProc radioButProc scrollBarProc testCntl thumbCntl useWFont vAxisOnly æKY pushButProc æFp Controls.p æT CONST æD pushButProc = 0; æC æKY checkBoxProc æFp Controls.p æT CONST æD checkBoxProc = 1; æC æKY radioButProc æFp Controls.p æT CONST æD radioButProc = 2; æC æKY useWFont æFp Controls.p æT CONST æD useWFont = 8; æC æKY scrollBarProc æFp Controls.p æT CONST æD scrollBarProc = 16; æC æKY inButton æFp Controls.p æT CONST æD inButton = 10; æC æKY inCheckBox æFp Controls.p æT CONST æD inCheckBox = 11; æC æKY inUpButton æFp Controls.p æT CONST æD inUpButton = 20; æC æKY inDownButton æFp Controls.p æT CONST æD inDownButton = 21; æC æKY inPageUp æFp Controls.p æT CONST æD inPageUp = 22; æC æKY inPageDown æFp Controls.p æT CONST æD inPageDown = 23; æC æKY inThumb æFp Controls.p æT CONST æD inThumb = 129; æC æKY popupMenuProc æFp Controls.p æT CONST æD popupMenuProc = 1008; { 63 * 16 } æC æKY inLabel æFp Controls.p æT CONST æD inLabel = 1; æC æKY inMenu æFp Controls.p æT CONST æD inMenu = 2; æC æKY inTriangle æFp Controls.p æT CONST æD inTriangle = 4; æC æKY popupTitleLeftJust æFp Controls.p æT CONST æD popupTitleLeftJust = $0000; æC æKY popupTitleCenterJust æFp Controls.p æT CONST æD popupTitleCenterJust = $0001; æC æKY popupTitleRightJust æFp Controls.p æT CONST æD popupTitleRightJust = $00FF; æC æKY noConstraint æFp Controls.p æT CONST æD { axis constraints for DragGrayRgn call } noConstraint = 0; æC æKY hAxisOnly æFp Controls.p æT CONST æD hAxisOnly = 1; æC æKY vAxisOnly æFp Controls.p æT CONST æD vAxisOnly = 2; æC æKY drawCntl æFp Controls.p æT CONST æD { control messages } drawCntl = 0; æC æKY testCntl æFp Controls.p æT CONST æD testCntl = 1; æC æKY calcCRgns æFp Controls.p æT CONST æD calcCRgns = 2; æC æKY initCntl æFp Controls.p æT CONST æD initCntl = 3; æC æKY dispCntl æFp Controls.p æT CONST æD dispCntl = 4; æC æKY posCntl æFp Controls.p æT CONST æD posCntl = 5; æC æKY thumbCntl æFp Controls.p æT CONST æD thumbCntl = 6; æC æKY dragCntl æFp Controls.p æT CONST æD dragCntl = 7; æC æKY autoTrack æFp Controls.p æT CONST æD autoTrack = 8; æC æKY cFrameColor æFp Controls.p æT CONST æD cFrameColor = 0; æC æKY cBodyColor æFp Controls.p æT CONST æD cBodyColor = 1; æC æKY cTextColor æFp Controls.p æT CONST æD cTextColor = 2; æC æKY cThumbColor æFp Controls.p æT CONST æD cThumbColor = 3; æC æKY calcCntlRgn æFp Controls.p æT CONST æD calcCntlRgn = 10; æC æKY calcThumbRgn æFp Controls.p æT CONST æD calcThumbRgn = 11; æC æKY ControlRecord ControlPtr ControlHandle æFp Controls.p æT RECORD æD ControlPtr = ^ControlRecord; ControlHandle = ^ControlPtr; ControlRecord = PACKED RECORD nextControl: ControlHandle; contrlOwner: WindowPtr; contrlRect: Rect; contrlVis: Byte; contrlHilite: Byte; contrlValue: INTEGER; contrlMin: INTEGER; contrlMax: INTEGER; contrlDefProc: Handle; contrlData: Handle; contrlAction: ProcPtr; contrlRfCon: LONGINT; contrlTitle: Str255; END; æC Every control is represented internally by a control record containing all pertinent information about that control. The control record contains the following: • A pointer to the window the control belongs to. • A handle to the next control in the window’s control list. • A handle to the control definition function. • The control’s title, if any. • A rectangle that completely encloses the control, which determines the control’s size and location within its window. The entire control, including the title of a check box or radio button, is drawn inside this rectangle. • An indication of whether the control is currently active and how it’s to be highlighted. • The current setting of the control (if this type of control retains a setting) and the minimum and maximum values the setting can assume. For check boxes and radio buttons, a setting of 0 means the control is off and 1 means it’s on. The control record also contains an indication of whether the control is currently visible or invisible. These terms refer only to whether the control is drawn in its window, not to whether you can see it on the screen. A control may be “visible” and still not appear on the screen, because it’s obscured by overlapping windows or other objects. There’s a field in the control record for a pointer to the control’s default action procedure. An action procedure defines some action to be performed repeatedly for as long as the user holds down the mouse button inside the control. The default action procedure may be used by the Control Manager function TrackControl if you call it without passing a pointer to an action procedure; this is discussed in detail in the description of TrackControl in the “Control Manager Routines” section. Finally, the control record includes a 32-bit reference value field, which is reserved for use by your application. You specify an initial reference value when you create a control, and can then read or change the reference value whenever you wish. The data type for a control record is called ControlRecord. A control record is referred to by a handle: TYPE ControlPtr = ^ControlRecord; ControlHandle = ^ControlPtr; The Control Manager functions for creating a control return a handle to a newly allocated control record; thereafter, your program should normally refer to the control by this handle. Most of the Control Manager routines expect a control handle as their first parameter. You can store into and access most of a control record’s fields with Control Manager routines, so normally you don’t have to know the exact field names. However, if you want more information about the exact structure of a control record—if you’re defining your own control types, for instance—it’s given below. _______________________________________________________________________________ »The ControlRecord Data Type The ControlRecord data type is defined as follows: TYPE ControlRecord = PACKED RECORD nextControl: ControlHandle; {next control} contrlOwner: WindowPtr; {control's window} contrlRect: Rect; {enclosing rectangle} contrlVis: Byte; {255 if visible} contrlHilite: Byte; {highlight state} contrlValue: INTEGER; {control's current setting} contrlMin: INTEGER; {control's minimum setting} contrlMax: INTEGER; {control's maximum setting} contrlDefProc: Handle; {control definition function} contrlData: Handle; {data used by contrlDefProc} contrlAction: ProcPtr; {default action procedure} contrlRfCon: LONGINT; {control's reference value} contrlTitle: Str255 {control's title} END; NextControl is a handle to the next control associated with this control’s window. All the controls belonging to a given window are kept in a linked list, beginning in the controlList field of the window record and chained together through the nextControl fields of the individual control records. The end of the list is marked by a NIL value; as new controls are created, they’re added to the beginning of the list. ContrlOwner is a pointer to the window that this control belongs to. ContrlRect is the rectangle that completely encloses the control, in the local coordinates of the control’s window. When contrlVis is 0, the control is currently invisible; when it’s 255, the control is visible. ContrlHilite specifies whether and how the control is to be highlighted, indicating whether it’s active or inactive. The HiliteControl procedure lets you set this field; see the description of HiliteControl for more information about the meaning of the field’s value. ContrlValue is the control’s current setting. For check boxes and radio buttons, 0 means the control is off and 1 means it’s on. For dials, the fields contrlMin and contrlMax define the range of possible settings; contrlValue may take on any value within that range. Other (custom) control types can use these three fields as they see fit. ContrlDefProc is a handle to the control definition function for this type of control. When you create a control, you identify its type with a control definition ID, which is converted into a handle to the control definition function and stored in the contrlDefProc field. Thereafter, the Control Manager uses this handle to access the definition function; you should never need to refer to this field directly. Note: When not running in 32-bit mode, the high-order byte of the contrlDefProc field contains some additional information that the Control Manager gets from the control definition ID; for details, see the section “Defining Your Own Controls”. ContrlData is reserved for use by the control definition function, typically to hold additional information specific to a particular control type. For example, the standard definition function for scroll bars uses this field for a handle to the region containing the scroll bar’s thumb. If no more than four bytes of additional information are needed, the definition function can store the information directly in the contrlData field rather than use a handle. ContrlAction is a pointer to the control’s default action procedure, if any. The Control Manager function TrackControl may call this procedure to respond to the user’s dragging the mouse inside the control. ContrlRfCon is the control’s reference value field, which the application may store into and access for any purpose. ContrlTitle is the control’s title, if any. æKY CtlCTab CCTabPtr CCTabHandle æFp Controls.p æT RECORD æD CCTabPtr = ^CtlCTab; CCTabHandle = ^CCTabPtr; CtlCTab = RECORD ccSeed: LONGINT; {reserved} ccRider: INTEGER; {see what you have done - reserved} ctSize: INTEGER; {usually 3 for controls} ctTable: ARRAY [0..3] OF ColorSpec; END; æC The contents and meaning of a control’s color table are determined by its control definition function (see “The Control Color Table Resource” section). The CTabHandle parameter used in the Color Control Manager routines provides a handle to the control color table. The components of a control color table are defined as follows: TYPE CCTabHandle = ^CCTabPtr; CCTabPtr = ^CtlCTab; CtlCTab = RECORD ccSeed: LONGINT; {not used for controls} ccRider: INTEGER; {not used for controls} ctSize: INTEGER; {number of entries in table –1} ctTable: cSpecArray {array of ColorSpec records} END; Field descriptions ccSeed The ccSeed field is unused in control color tables. ccRider The ccRider field is unused in control color tables. ctSize The ctSize field defines the number of elements in the table, minus one. For controls drawn with the standard definition procedure, this field is always 3. ctTable The ctTable field holds an array of colorSpec records. Each colorSpec is made up of a partIdentifier field and a partRGB field. The partIdentifier field holds an integer which associates an RGBColor to a particular part of the control. The definition procedures attempt to find the appropriate part identifier when preparing to draw a part. If that part identifier is not found, the first color in the table is used to draw the part. The part identifiers can appear in any order in the table. The partRGB field specifies a standard RGB color record, indicating what absolute color will be used to draw the control part found in the partIdentifier field. A standard control color table is shown in Figure 6. •••Refer to Figure 6.••• Figure 6–Control Color Table The 'cctb' resource is an exact image of this control table data structure, and is stored in the same format as 'clut' color table resources. Standard buttons, check boxes, and radio buttons use a four-element color table with part identifiers as shown below: cFrameColor (0) Frame color cBodyColor (1) Fill color for body of control cTextColor (2) Text color cThumbColor (3) Unused When highlighted, plain buttons exchange their body and text colors (colors 1 and 2); check boxes and radio buttons change their appearance without changing colors. All three types indicate deactivation by dimming their text with no change in colors. Standard scroll bars use a four-element color table with part identifiers as shown below: cFrameColor (0) Frame color, foreground color for shaft and arrows cBodyColor (1 Background color for shaft and arrows cTextColor (2) Unused cThumbColor (3) Fill color for thumb When highlighted, the arrows are filled with the foreground color (color 0) within the arrow outline. A deactivated scroll bar shows no indicator, and displays its shaft in solid background color (color 1), with no pattern. The 'cctb' resource = 0 is read into the application heap when the application starts, and serves as the default control color table. The last record in the auxiliary control list points to the default 'cctb' resource. When drawing a control, the standard control definition function searches the list for an auxiliary control record whose acOwner points to the control being drawn. If it finds such a record, it uses the color table designated by that record; if it doesn’t find one before reaching the default record at the end of the list, it uses the default color table instead. All types of controls share the same default record. The default auxiliary control record is recognized by NIL values in both its acNext and acOwner fields; the application must not change these fields. A nonstandard control definition function can use color tables of any desired size and define their contents in any way it wishes, except that part indices 1 to 127 are reserved for system definition. Any such nonstandard function should take care to bypass the defaulting mechanism just described, by allocating an explicit auxiliary record for every control it creates. æKY AuxCtlRec AuxCtlPtr AuxCtlHandle æFp Controls.p æT RECORD æD AuxCtlPtr = ^AuxCtlRec; AuxCtlHandle = ^AuxCtlPtr; AuxCtlRec = RECORD acNext: AuxCtlHandle; {handle to next AuxCtlRec} acOwner: ControlHandle; {handle for aux record's control} acCTable: CCTabHandle; {color table for this control} acFlags: INTEGER; {misc flag byte} acReserved: LONGINT; {reserved for use by Apple} acRefCon: LONGINT; {for use by application} END; æC The information needed for drawing controls in color is kept in a linked list of auxiliary control records, beginning in the global variable AuxCtlHead. (Notice that there is just one global list for all controls in all windows, not a separate one for each window.) Each window record has a handle to the list of controls. Figure 5 shows the auxiliary control list structure. •••Refer to Figure 5.••• Figure 5–Auxiliary Control List Each auxiliary control record is a relocatable object residing in the application heap. The most important information it holds is a handle to the control’s individual color table (see the “Control Color Tables” section). The rest of the record consists of a link to the next record in the list, a field that identifies the control’s owner, a 4-byte field reserved for future expansion, and a 4-byte reference constant for use by the application: TYPE AuxCtlHandle = ^AuxCtlPtr; AuxCtlPtr = ^AuxCtlRec; AuxCtlRec = RECORD acNext: AuxCtlHandle; {handle to next record in list} acOwner: ControlHandle; {handle to owning control} acCTable: CCTabHandle; {handle to control's color } { table} acFlags: INTEGER; {miscellaneous flags; reserved} acReserved: LONGINT; {reserved for future expansion} acRefCon: LONGINT {reserved for application use} END; Field descriptions acNext The acNext field contains a handle to the next record in the auxiliary control list. acOwner The acOwner field contains the handle of the control to which this auxiliary record belongs. Used as an ID field. acCTable The acCTable contains the handle to the control’s color table (see “Control Color Tables” below). acFlags The acFlags field contains miscellaneous flags for use by the Control Manager; this field is reserved. acReserved The acReserved field is reserved for future expansion; this must be set to 0 for future compatibility. acRefCon The acRefCon field is a reference constant for use by the application. Not every control needs an auxiliary control record. When an application is started, a resource containing a default color table is loaded from the system resource file; this resource defines a standard set of control colors. Since there is no InitControls routine, this happens when an application calls InitWindows. Separate auxiliary control records are needed only for controls whose color usage differs from the default. Each such nonstandard control must have its own auxiliary record, even if it uses the same colors as another control. This allows two or more auxiliary records to share the same control color table. If the control color table is a resource, it won’t be deleted by DisposeControl. When using an auxiliary record that is not stored as a resource, the application should not deallocate the color table if another control is still using it. A control created from scratch will initially have no auxiliary control record. If it is to use nonstandard colors, it must be given an auxiliary record and a color table with SetCtlColor (see the “Control Manager Routines” section). Such a control should normally be made invisible at creation and then displayed with ShowControl after the colors are set. For controls created from a 'CNTL' resource, the color table can be specified as a resource as well. See the section titled “The Control Color Table Resource”. A/UX systems: When using 32-bit mode. every control has its own auxiliary record. If there is no specific set of control colors for this control, the acCTable will point to the default color table. æKY NewControl æFp Controls.p æT FUNCTION æTN A954 æD FUNCTION NewControl(theWindow: WindowPtr;boundsRect: Rect;title: Str255; visible: BOOLEAN;value: INTEGER;min: INTEGER;max: INTEGER;procID: INTEGER; refCon: LONGINT): ControlHandle; INLINE $A954; æDT myVariable := NewControl(theWindow,boundsRect,title,visible,value,min,max,procID,refCon); æMM æRI I-319, P-112, 114, 177 æC NewControl creates a control, adds it to the beginning of theWindow’s control list, and returns a handle to the new control. The values passed as parameters are stored in the corresponding fields of the control record, as described below. The field that determines highlighting is set to 0 (no highlighting) and the pointer to the default action procedure is set to NIL (none). Note: The control definition function may do additional initialization, including changing any of the fields of the control record. The only standard control for which additional initialization is done is the scroll bar; its control definition function allocates space for a region to hold the thumb and stores the region handle in the contrlData field of the control record. TheWindow is the window the new control will belong to. All coordinates pertaining to the control will be interpreted in this window’s local coordinate system. BoundsRect, given in theWindow’s local coordinates, is the rectangle that encloses the control and thus determines its size and location. Note the following about the enclosing rectangle for the standard controls: • Simple buttons are drawn to fit the rectangle exactly. (The control definition function calls the QuickDraw procedure FrameRoundRect.) To allow for the tallest characters in the system font, there should be at least a 20-point difference between the top and bottom coordinates of the rectangle. • For check boxes and radio buttons, there should be at least a 16-point difference between the top and bottom coordinates. • By convention, scroll bars are 16 pixels wide, so there should be a 16-point difference between the left and right (or top and bottom) coordinates. (If there isn’t, the scroll bar will be scaled to fit the rectangle.) A standard scroll bar should be at least 48 pixels long, to allow room for the scroll arrows and thumb. Title is the control’s title, if any (if none, you can just pass the empty string as the title). Be sure the title will fit in the control’s enclosing rectangle; if it won’t it will be truncated on the right for check boxes and radio buttons, or centered and truncated on both ends for simple buttons. Note: Some non-Roman systems write text from right-to-left, in which case radio buttons and check boxes are drawn with their titles on the left of the control. They are also truncated on the left. See the Script Manager chapter for more information. If the visible parameter is TRUE, NewControl draws the control. Note: It does not use the standard window updating mechanism, but instead draws the control immediately in the window. The min and max parameters define the control’s range of possible settings; the value parameter gives the initial setting. For controls that don’t retain a setting, such as buttons, the values you supply for these parameters will be stored in the control record but will never be used. So it doesn’t matter what values you give for those controls—0 for all three parameters will do. For controls that just retain an on-or-off setting, such as check boxes or radio buttons, min should be 0 (meaning the control is off) and max should be 1 (meaning it’s on). For dials, you can specify whatever values are appropriate for min, max, and value. ProcID is the control definition ID, which leads to the control definition function for this type of control. (The function is read into memory if it isn’t already in memory.) The control definition IDs for the standard control types are listed above under “Controls and Resources”. Control definition IDs for custom control types are discussed later under “Defining Your Own Controls”. RefCon is the control’s reference value, set and used only by your application. æKY SetCTitle æFp Controls.p æT PROCEDURE æTN A95F æD PROCEDURE SetCTitle(theControl: ControlHandle;title: Str255); INLINE $A95F; æDT SetCTitle(theControl,title); æMM æRI I-321 æC SetCTitle sets theControl’s title to the given string and redraws the control. æKY GetCTitle æFp Controls.p æT PROCEDURE æTN A95E æD PROCEDURE GetCTitle(theControl: ControlHandle;VAR title: Str255); INLINE $A95E; æDT GetCTitle(theControl,title); æRI I-321 æC GetCTitle returns theControl’s title as the value of the title parameter. æKY GetNewControl æFp Controls.p æT FUNCTION æTN A9BE æD FUNCTION GetNewControl(controlID: INTEGER;owner: WindowPtr): ControlHandle; INLINE $A9BE; æDT myVariable := GetNewControl(controlID,owner); æMM æRT 203 æRI I-321, P-112, 113, 114, 172 æC GetNewControl creates a control from a control template stored in a resource file, adds it to the beginning of theWindow’s control list, and returns a handle to the new control. ControlID is the resource ID of the template. GetNewControl works exactly the same as NewControl (above), except that it gets the initial values for the new control’s fields from the specified control template instead of accepting them as parameters. If the control template can’t be read from the resource file, GetNewControl returns NIL. It releases the memory occupied by the resource before returning. The system default control colors are stored in the System file and ROMResources as 'cctb' resource = 0. By including a 'cctb' resource = 0 in your application, it is possible to change the default colors that will be used for all controls, unless a specific 'cctb' exists for a control defined within the application. When you use GetNewControl for the control resource 'CNTL', GetNewControl will attempt to load a 'cctb' resource with the same ID as the 'CNTL' resource ID, if one is present. It then executes the SetCtlColor call. The following part identifiers for control elements should be present in the ColorSpec.value field: cFrameColor (0) Frame color cBodyColor (1) Fill color for body of control cTextColor (2) Text color cThumbColor (3) Thumb color These identifiers may be present in any order; for instance, the text or indicator color values may be stored before the fill and frame colors in the ColorSpec record structure. If a part identifier is not found, then the first color in the color table will be used. æKY DisposeControl æFp Controls.p æT PROCEDURE æTN A955 æD PROCEDURE DisposeControl(theControl: ControlHandle); INLINE $A955; æDT DisposeControl(theControl); æMM æRI I-321, P-168 æC Assembly-language note: The macro you invoke to call DisposeControl from assembly language is named _DisposControl. DisposeControl removes theControl from the screen, deletes it from its window’s control list, and releases the memory occupied by the control record and any data structures associated with the control. æKY KillControls æFp Controls.p æT PROCEDURE æTN A956 æD PROCEDURE KillControls(theWindow: WindowPtr); INLINE $A956; æDT KillControls(theWindow); æMM æRI I-321, P-113, 175 æC KillControls disposes of all controls associated with theWindow by calling DisposeControl (above) for each. Note: Remember that the Window Manager procedures CloseWindow and DisposeWindow automatically dispose of all controls associated with the given window. æKY HideControl æFp Controls.p æT PROCEDURE æTN A958 æD PROCEDURE HideControl(theControl: ControlHandle); INLINE $A958; æDT HideControl(theControl); æMM æRI I-322, P-113, 114, 174 æC HideControl makes theControl invisible. It fills the region the control occupies within its window with the background pattern of the window’s grafPort. It also adds the control’s enclosing rectangle to the window’s update region, so that anything else that was previously obscured by the control will reappear on the screen. If the control is already invisible, HideControl has no effect. æKY ShowControl æFp Controls.p æT PROCEDURE æTN A957 æD PROCEDURE ShowControl(theControl: ControlHandle); INLINE $A957; æDT ShowControl(theControl); æMM æRT 197 æRI I-322, P-113, 114, 181 æC ShowControl makes theControl visible. The control is drawn in its window but may be completely or partially obscured by overlapping windows or other objects. If the control is already visible, ShowControl has no effect. æKY DrawControls æFp Controls.p æT PROCEDURE æTN A969 æD PROCEDURE DrawControls(theWindow: WindowPtr); INLINE $A969; æDT DrawControls(theWindow); æRT 203 æRI I-322, P-169 æC DrawControls draws all controls currently visible in theWindow. The controls are drawn in reverse order of creation; thus in case of overlap the earliest-created controls appear frontmost in the window. Note: Window Manager routines such as SelectWindow, ShowWindow, and BringToFront do not automatically call DrawControls to display the window’s controls. They just add the appropriate regions to the window’s update region, generating an update event. Your program should always call DrawControls explicitly upon receiving an update event for a window that contains controls. æKY Draw1Control æFp Controls.p æT PROCEDURE æTN A96D æD PROCEDURE Draw1Control(theControl: ControlHandle); INLINE $A96D; æDT Draw1Control(theControl); æMM æRI IV-53 æC [128K ROM] Draw1Control draws the specified control if it’s visible within the window. æKY HiliteControl æFp Controls.p æT PROCEDURE æTN A95D æD PROCEDURE HiliteControl(theControl: ControlHandle;hiliteState: INTEGER); INLINE $A95D; æDT HiliteControl(theControl,hiliteState); æMM æRI I-322 æC HiliteControl changes the way theControl is highlighted. HiliteState has one of the following values: • The value 0 means no highlighting. (The control is active.) • A value between 1 and 253 is interpreted as a part code designating the part of the (active) control to be highlighted. • The value 255 means that the control is to be made inactive and highlighted accordingly. Note: The value 254 should not be used; this value is reserved for future use. HiliteControl calls the control definition function to redraw the control with its new highlighting. æKY UpdtControl æFp Controls.p æT PROCEDURE æTN A953 æD PROCEDURE UpdtControl(theWindow: WindowPtr;updateRgn: RgnHandle); INLINE $A953; æDT UpdtControl(theWindow,updateRgn); æMM æRI IV-53 æC [128K ROM] UpdtControl is a faster version of the DrawControls procedure. Instead of drawing all of the controls in theWindow, UpdtControl draws only the controls that are in the specified update region. UpdtControl is called in response to an update event, and is usually bracketed by calls to the Window Manager procedures BeginUpdate and EndUpdate. UpdateRgn should be set to the visRgn of theWindow’s port (for more details, see the BeginUpdate procedure in the Window Manager chapter). Note: In general, controls are in a dialog box and are automatically drawn by the DrawDialog procedure. æKY MoveControl æFp Controls.p æT PROCEDURE æTN A959 æD PROCEDURE MoveControl(theControl: ControlHandle;h: INTEGER;v: INTEGER); INLINE $A959; æDT MoveControl(theControl,h,v); æMM æRI I-325, P-113, 176 æC MoveControl moves theControl to a new location within its window. The top left corner of the control’s enclosing rectangle is moved to the horizontal and vertical coordinates h and v (given in the local coordinates of the control’s window); the bottom right corner is adjusted accordingly, to keep the size of the rectangle the same as before. If the control is currently visible, it’s hidden and then redrawn at its new location. æKY SizeControl æFp Controls.p æT PROCEDURE æTN A95C æD PROCEDURE SizeControl(theControl: ControlHandle;w: INTEGER;h: INTEGER); INLINE $A95C; æDT SizeControl(theControl,w,h); æMM æRI I-326, P-113, 181 æC SizeControl changes the size of theControl’s enclosing rectangle. The bottom right corner of the rectangle is adjusted to set the rectangle’s width and height to the number of pixels specified by w and h; the position of the top left corner is not changed. If the control is currently visible, it’s hidden and then redrawn in its new size. æKY SetCtlValue æFp Controls.p æT PROCEDURE æTN A963 æD PROCEDURE SetCtlValue(theControl: ControlHandle;theValue: INTEGER); INLINE $A963; æDT SetCtlValue(theControl,theValue); æMM æRT 197 æRI I-326 æC SetCtlValue sets theControl’s current setting to theValue and redraws the control to reflect the new setting. For check boxes and radio buttons, the value 1 fills the control with the appropriate mark, and 0 clears it. For scroll bars, SetCtlValue redraws the thumb where appropriate. If the specified value is out of range, it’s forced to the nearest endpoint of the current range (that is, if theValue is less than the minimum setting, SetCtlValue sets the current setting to the minimum; if theValue is greater than the maximum setting, it sets the current setting to the maximum). æKY GetCtlValue æFp Controls.p æT FUNCTION æTN A960 æD FUNCTION GetCtlValue(theControl: ControlHandle): INTEGER; INLINE $A960; æDT myVariable := GetCtlValue(theControl); æRI I-326, P-114, 171 æC GetCtlValue returns theControl’s current setting. æKY SetCtlMin æFp Controls.p æT PROCEDURE æTN A964 æD PROCEDURE SetCtlMin(theControl: ControlHandle;minValue: INTEGER); INLINE $A964; æDT SetCtlMin(theControl,minValue); æMM æRI I-326 æC Assembly-language note: The macro you invoke to call SetCtlMin from assembly language is named _SetMinCtl. SetCtlMin sets theControl’s minimum setting to minValue and redraws the control to reflect the new range. If the control’s current setting is less than minValue, the setting is changed to the new minimum. æKY GetCtlMin æFp Controls.p æT FUNCTION æTN A961 æD FUNCTION GetCtlMin(theControl: ControlHandle): INTEGER; INLINE $A961; æDT myVariable := GetCtlMin(theControl); æRI I-327 æC Assembly-language note: The macro you invoke to call GetCtlMin from assembly language is named _GetMinCtl. GetCtlMin returns theControl’s minimum setting. æKY SetCtlMax æFp Controls.p æT PROCEDURE æTN A965 æD PROCEDURE SetCtlMax(theControl: ControlHandle;maxValue: INTEGER); INLINE $A965; æDT SetCtlMax(theControl,maxValue); æMM æRI I-327 æC Assembly-language note: The macro you invoke to call SetCtlMax from assembly language is named _SetMaxCtl. SetCtlMax sets theControl’s maximum setting to maxValue and redraws the control to reflect the new range. If the control’s current setting is greater than maxValue, the setting is changed to the new maximum. Note: If you set the maximum setting of a scroll bar equal to its minimum setting, the control definition function will make the scroll bar inactive. æKY GetCtlMax æFp Controls.p æT FUNCTION æTN A962 æD FUNCTION GetCtlMax(theControl: ControlHandle): INTEGER; INLINE $A962; æDT myVariable := GetCtlMax(theControl); æRI I-327 æC Assembly-language note: The macro you invoke to call GetCtlMax from assembly language is named _GetMaxCtl. GetCtlMax returns theControl’s maximum setting. æKY SetCRefCon æFp Controls.p æT PROCEDURE æTN A95B æD PROCEDURE SetCRefCon(theControl: ControlHandle;data: LONGINT); INLINE $A95B; æDT SetCRefCon(theControl,data); æRI I-327 æC SetCRefCon sets theControl’s reference value to the given data. æKY GetCRefCon æFp Controls.p æT FUNCTION æTN A95A æD FUNCTION GetCRefCon(theControl: ControlHandle): LONGINT; INLINE $A95A; æDT myVariable := GetCRefCon(theControl); æRI I-327 æC GetCRefCon returns theControl’s current reference value. æKY SetCtlAction æFp Controls.p æT PROCEDURE æTN A96B æD PROCEDURE SetCtlAction(theControl: ControlHandle;actionProc: ProcPtr); INLINE $A96B; æDT SetCtlAction(theControl,actionProc); æRI I-328 æC SetCtlAction sets theControl’s default action procedure to actionProc. æKY GetCtlAction æFp Controls.p æT FUNCTION æTN A96A æD FUNCTION GetCtlAction(theControl: ControlHandle): ProcPtr; INLINE $A96A; æDT myVariable := GetCtlAction(theControl); æRI I-328, IV-53 æC GetCtlAction returns a pointer to theControl’s default action procedure, if any. (It returns whatever is in that field of the control record.) æKY DragControl æFp Controls.p æT PROCEDURE æTN A967 æD PROCEDURE DragControl(theControl: ControlHandle;startPt: Point;limitRect: Rect; slopRect: Rect;axis: INTEGER); INLINE $A967; æDT DragControl(theControl,startPt,limitRect,slopRect,axis); æMM æRI I-325 æC Called with the mouse button down inside theControl, DragControl pulls a dotted outline of the control around the screen, following the movements of the mouse until the button is released. When the mouse button is released, DragControl calls MoveControl to move the control to the location to which it was dragged. Note: Before beginning to follow the mouse, DragControl calls the control definition function to allow it to do its own “custom dragging” if it chooses. If the definition function doesn’t choose to do any custom dragging, DragControl uses the default method of dragging described here. The startPt, limitRect, slopRect, and axis parameters have the same meaning as for the Window Manager function DragGrayRgn. These parameters are reviewed briefly below; see the description of DragGrayRgn in the Window Manager chapter for more details. • StartPt is assumed to be the point where the mouse button was originally pressed, in the local coordinates of the control’s window. • LimitRect limits the travel of the control’s outline, and should normally coincide with or be contained within the window’s content region. • SlopRect allows the user some “slop” in moving the mouse; it should completely enclose limitRect. • The axis parameter allows you to constrain the control’s motion to only one axis. It has one of the following values: CONST noConstraint = 0; {no constraint} hAxisOnly = 1; {horizontal axis only} vAxisOnly = 2; {vertical axis only} Assembly-language note: Like TrackControl, DragControl invokes the macro _DragTheRgn, so you can use the global variables DragHook and DragPattern. æKY TestControl æFp Controls.p æT FUNCTION æTN A966 æD FUNCTION TestControl(theControl: ControlHandle;thePt: Point): INTEGER; INLINE $A966; æDT myVariable := TestControl(theControl,thePt); æMM æRI I-325 æC If theControl is visible and active, TestControl tests which part of the control contains thePoint (in the local coordinates of the control’s window); it returns the corresponding part code, or 0 if the point is outside the control. If the control is invisible or inactive, TestControl returns 0. TestControl is called by FindControl and TrackControl; normally you won’t need to call it yourself. æKY TrackControl æFp Controls.p æT FUNCTION æTN A968 æD FUNCTION TrackControl(theControl: ControlHandle;thePoint: Point;actionProc: ProcPtr): INTEGER; INLINE $A968; æDT myVariable := TrackControl(theControl,thePoint,actionProc); æMM æRI I-323, P-114, 184 æC When the mouse button is pressed in a visible, active control, the application should call TrackControl with theControl equal to the control handle and startPt equal to the point where the mouse button was pressed (in the local coordinates of the control’s window). TrackControl follows the movements of the mouse and responds in whatever way is appropriate until the mouse button is released; the exact response depends on the type of control and the part of the control in which the mouse button was pressed. If highlighting is appropriate, TrackControl does the highlighting, and undoes it before returning. When the mouse button is released, TrackControl returns with the part code if the mouse is in the same part of the control that it was originally in, or with 0 if not (in which case the application should do nothing). If the mouse button was pressed in an indicator, TrackControl drags a dotted outline of it to follow the mouse. When the mouse button is released, TrackControl calls the control definition function to reposition the control’s indicator. The control definition function for scroll bars responds by redrawing the thumb, calculating the control’s current setting based on the new relative position of the thumb, and storing the current setting in the control record; for example, if the minimum and maximum settings are 0 and 10, and the thumb is in the middle of the scroll bar, 5 is stored as the current setting. The application must then scroll to the corresponding relative position in the document. TrackControl may take additional actions beyond highlighting the control or dragging the indicator, depending on the value passed in the actionProc parameter, as described below. The following tells you what to pass for the standard control types; for a custom control, what you pass will depend on how the control is defined. • If actionProc is NIL, TrackControl performs no additional actions. This is appropriate for simple buttons, check boxes, radio buttons, and the thumb of a scroll bar. • ActionProc may be a pointer to an action procedure that defines some action to be performed repeatedly for as long as the user holds down the mouse button. (See below for details.) • If actionProc is POINTER(–1), TrackControl looks in the control record for a pointer to the control’s default action procedure. If that field of the control record contains a procedure pointer, TrackControl uses the action procedure it points to; if the field contains POINTER (–1), TrackControl calls the control definition function to perform the necessary action. (If the field contains NIL, TrackControl does nothing.) The action procedure in the control definition function is described in the section “Defining Your Own Controls”. The following paragraphs describe only the action procedure whose pointer is passed in the actionProc parameter or stored in the control record. If the mouse button was pressed in an indicator, the action procedure (if any) should have no parameters. This procedure must allow for the fact that the mouse may not be inside the original control part. If the mouse button was pressed in a control part other than an indicator, the action procedure should be of the form PROCEDURE MyAction (theControl: ControlHandle; partCode: INTEGER); In this case, TrackControl passes the control handle and the part code to the action procedure. (It passes 0 in the partCode parameter if the mouse has moved outside the original control part.) As an example of this type of action procedure, consider what should happen when the mouse button is pressed in a scroll arrow or paging region in a scroll bar. For these cases, your action procedure should examine the part code to determine exactly where the mouse button was pressed, scroll up or down a line or page as appropriate, and call SetCtlValue to change the control’s setting and redraw the thumb. Warning: Since it has a different number of parameters depending on whether the mouse button was pressed in an indicator or elsewhere, the action procedure you pass to TrackControl (or whose pointer you store in the control record) can be set up for only one case or the other. If you store a pointer to a default action procedure in a control record, be sure it will be used only when appropriate for that type of action procedure. The only way to specify actions in response to all mouse-down events in a control, regardless of whether they’re in an indicator, is via the control definition function. Assembly-language note: If you store a pointer to a procedure in the global variable DragHook, that procedure will be called repeatedly (with no parameters) for as long as the user holds down the mouse button. TrackControl invokes the Window Manager macro _DragTheRgn, which calls the DragHook procedure. _DragTheRgn uses the pattern stored in the global variable DragPattern for the dragged outline of the indicator. æKY FindControl æFp Controls.p æT FUNCTION æTN A96C æD FUNCTION FindControl(thePoint: Point;theWindow: WindowPtr;VAR theControl: ControlHandle): INTEGER; INLINE $A96C; æDT myVariable := FindControl(thePoint,theWindow,theControl); æMM æRI I-323, P-98, 114, 170 æC When the Window Manager function FindWindow reports that the mouse button was pressed in the content region of a window, and the window contains controls, the application should call FindControl with theWindow equal to the window pointer and thePoint equal to the point where the mouse button was pressed (in the window’s local coordinates). FindControl tells which of the window’s controls, if any, the mouse button was pressed in: • If it was pressed in a visible, active control, FindControl sets the whichControl parameter to the control handle and returns a part code identifying the part of the control that it was pressed in. • If it was pressed in an invisible or inactive control, or not in any control, FindControl sets whichControl to NIL and returns 0 as its result. Warning: Notice that FindControl expects the mouse point in the window’s local coordinates, whereas FindWindow expects it in global coordinates. Always be sure to convert the point to local coordinates with the QuickDraw procedure GlobalToLocal before calling FindControl. Note: FindControl also returns NIL for whichControl and 0 as its result if the window is invisible or doesn’t contain the given point. In these cases, however, FindWindow wouldn’t have returned this window in the first place, so the situation should never arise. æKY SetCtlColor æFp Controls.p æT PROCEDURE æTN AA43 æD PROCEDURE SetCtlColor(theControl: ControlHandle;newColorTable: CCTabHandle); INLINE $AA43; æDT SetCtlColor(theControl,newColorTable); æMM æRI V-222 æC [Macintosh II] The SetCtlColor procedure sets or modifies a control’s color table. If the control currently has no auxiliary control record, a new one is created with the given color table and added to the head of the auxiliary control list. If there is already an auxiliary record for the control, its color table is replaced by the contents of newColorTable. If newColorTable has the same contents as the default color table, the control’s existing auxiliary record and color table are removed from the auxiliary control list and deallocated. If theControl = NIL, the operation modifies the default color table itself. If the control is visible, it will be redrawn by SetCtlColor using the new color table. æKY GetAuxCtl æFp Controls.p æT FUNCTION æTN AA44 æD FUNCTION GetAuxCtl(theControl: ControlHandle;VAR acHndl: AuxCtlHandle): BOOLEAN; INLINE $AA44; æDT myVariable := GetAuxCtl(theControl,acHndl); æMM æRI V-222 æC [Macintosh II] The GetAuxCtl function returns a handle to a control’s AuxCtlRec: • If the given control has its own color table, the function returns TRUE. • If the control used the default color set, the function returns FALSE. • If the control asked to receive the default color set (theControl = NIL), then the function returns TRUE. æKY GetCVariant æFp Controls.p æT FUNCTION æTN A809 æD FUNCTION GetCVariant(theControl: ControlHandle): INTEGER; INLINE $A809; æDT myVariable := GetCVariant(theControl); æRI V-222 æC [Macintosh Plus, Macintosh SE, and Macintosh II] The GetVariant function returns the variant control value for the control described by theControl. This value was formerly stored in the high four bits of the control defproc handle; for future compatibility, use the GetCVariant routine to access this value. æKY CursorCtl.p æKL Hide_Cursor InitCursorCtl RotateCursor Show_Cursor SpinCursor Acur acurHandle acurPtr ARROW_CURSOR CROSS_CURSOR Cursors HIDDEN_CURSOR I_BEAM_CURSOR PLUS_CURSOR WATCH_CURSOR æKY Acur acurPtr acurHandle æFp CursorCtl.p æT TYPE æD acurPtr = ^Acur; acurHandle = ^acurPtr; Acur = RECORD n: INTEGER; {Number of cursors ("frames of film")} index: INTEGER; { Next frame to show <for internal use>} frame1: INTEGER; {'CURS' resource id for frame #1} fill1: INTEGER; {<for internal use>} frame2: INTEGER; {'CURS' resource id for frame #2} fill2: INTEGER; {<for internal use>} frameN: INTEGER; {'CURS' resource id for frame #N} fillN: INTEGER; {<for internal use>} END; æKY Cursors HIDDEN_CURSOR I_BEAM_CURSOR CROSS_CURSOR PLUS_CURSOR WATCH_CURSOR ARROW_CURSOR æFp CursorCtl.p æD Cursors = (HIDDEN_CURSOR,I_BEAM_CURSOR,CROSS_CURSOR,PLUS_CURSOR,WATCH_CURSOR, ARROW_CURSOR); æKY Hide_Cursor æFp CursorCtl.p æT PROCEDURE æD PROCEDURE Hide_Cursor; æDT Hide_Cursor; æC { Hide the cursor if it is showing.This is this unit's call to the Mac HideCursor routine.Thus the Mac cursor level is decremented by one when this routine is called. } æKY InitCursorCtl æFp CursorCtl.p æT PROCEDURE æD PROCEDURE InitCursorCtl(newCursors: UNIV acurHandle); æDT InitCursorCtl(newCursors); æC { Initialize the CursorCtl unit. This should be called once prior to calling RotateCursor or SpinCursor. It need not be called if only Hide_Cursor or Show_Cursor are used. If NewCursors is NULL, InitCursorCtl loads in the 'acur' resource and the 'CURS' resources specified by the 'acur' resource ids. If any of the resources cannot be loaded, the cursor will not be changed. The 'acur' resource is assumed to either be in the currently running tool or application, or the MPW Shell for a tool, or in the System file. The 'acur' resource id must be 0 for a tool or application, 1 for the Shell, and 2 for the System file. If NewCursors is not NULL, it is ASSUMED to be a handle to an 'acur' formatted resource designated by the caller and it will be used instead of doing a GetResource on 'acur'. Note, if RotateCursor or SpinCursor are called without calling InitCursorCtl, then RotateCursor and SpinCursor will do the call for the user the first time it is called. However, the possible disadvantage of using this technique is that the resource memory allocated may have undesirable affect (fragmentation?) on the application. Using InitCursorCtl has the advantage of causing the allocation at a specific time determined by the user. Caution: InitCursorCtl MODIFIES the 'acur' resource in memory. Specifically, it changes each FrameN/fillN integer pair to a handle to the corresponding 'CURS' resource also in memory. Thus if NewCursors is not NULL when InitCursorCtl is called, the caller must guarantee NewCursors always points to a "fresh" copy of an 'acur' resource. This need only be of concern to a caller who wants to repeatly use multiple 'acur' resources during execution of their programs. } æKY RotateCursor æFp CursorCtl.p æT PROCEDURE æD PROCEDURE RotateCursor(counter: LONGINT); æDT RotateCursor(counter); æC { RotateCursor is called to rotate the "I am active" "beach ball" cursor, or to animate whatever sequence of cursors set up by InitCursorCtl. The next cursor ("frame") is used when Counter % 32 = 0 (Counter is some kind of incrementing or decrementing index maintained by the caller). A positive counter sequences forward through the cursors (e.g., it rotates the "beach ball" cursor clockwise), and a negative cursor sequences through the cursors backwards (e.g., it rotates the "beach ball" cursor counterclockwise). Note, RotateCursor just does a Mac SetCursor call for the proper cursor picture. It is assumed the cursor is visible from a prior Show_Cursor call. } æKY Show_Cursor æFp CursorCtl.p æT PROCEDURE æD PROCEDURE Show_Cursor(cursorKind: Cursors); æDT Show_Cursor(cursorKind); æC { Increment the cursor level, which may have been decremented by Hide_Cursor, and display the specified cursor if the level becomes 0 (it is never incremented beyond 0).The CursorKind is the kind of cursor to show. It is one of the values HIDDEN_CURSOR, I_BEAM_CURSOR, CROSS_CURSOR, PLUS_CURSOR, WATCH_CURSOR, and ARROW_CURSOR. Except for HIDDEN_CURSOR, a Mac SetCursor is done for the specified cursor prior to doing a ShowCursor. HIDDEN_CURSOR just causes a ShowCursor call. Note, ARROW_CURSOR will only work correctly if there is already a grafPort set up pointed to by 0(A5). } æKY SpinCursor æFp CursorCtl.p æT PROCEDURE æD PROCEDURE SpinCursor(increment: INTEGER); æDT SpinCursor(increment); æC { SpinCursor is similar in function to RotateCursor, except that instead of passing a counter, an Increment is passed an added to a counter maintained here. SpinCursor is provided for those users who do not happen to have a convenient counter handy but still want to use the spinning "beach ball" cursor, or any sequence of cursors set up by InitCursorCtl. A positive increment sequences forward through the curos (rotating the "beach ball" cursor clockwise), and a negative increment sequences backward through the cursors (rotating the "beach ball" cursor counter-clockwise). A zero value for the increment resets the counter to zero. Note, it is the increment, and not the value of the counter that determines the sequencing direction of the cursor (and hence the spin direction of the "beach ball" cursor). } æKY DatabaseAccess.p æKL DBBreak DBDisposeQuery DBEnd DBExec DBGetConnInfo DBGetErr DBGetItem DBGetNewQuery DBGetQueryResults DBGetResultHandler DBGetSessionNum DBInit DBInstallResultHandler DBKill DBRemoveResultHandler DBResultsToText DBSend DBSendItem DBStartQuery DBState DBUnGetItem InitDBPack QuitDBPack DBAsyncParamBlockRec DBAsyncParmBlkPtr DBColInfoRecord kDBAboutToInit kDBExecComplete kDBGetItemComplete kDBGetQueryResultsComplete kDBInitComplete kDBLastColFlag kDBSendComplete kDBStartQueryComplete kDBUpdateWind kDBWaitForever QueryArray QueryHandle QueryListHandle QueryListPtr QueryPtr QueryRecord rcDBAsyncNotSupp rcDBBadAsyncPB rcDBBadDDEV rcDBBadSessID rcDBBadSessNum rcDBBadType rcDBBreak rcDBError rcDBExec rcDBNoHandler rcDBNull rcDBPackNotInited rcDBValue rcDBWrongVersion ResListElem ResListHandle ResultsRecord typeAnyType typeBoolean typeChar typeColBreak typeDate typeDecimal typeDiscard typeFloat typeInteger typeLBin typeLChar typeMoney typeNone typeRowBreak typeSMFloat typeSMInt typeTime typeTimeStamp typeUnknown typeVBin typeVChar æKY rcDBNull æFp DatabaseAccess.p æT CONST æD { OSErr error and status codes } rcDBNull = -800; æC æKY rcDBValue æFp DatabaseAccess.p æT CONST æD rcDBValue = -801; æC æKY rcDBError æFp DatabaseAccess.p æT CONST æD rcDBError = -802; æC æKY rcDBBadType æFp DatabaseAccess.p æT CONST æD rcDBBadType = -803; æC æKY rcDBBreak æFp DatabaseAccess.p æT CONST æD rcDBBreak = -804; æC æKY rcDBExec æFp DatabaseAccess.p æT CONST æD rcDBExec = -805; æC æKY rcDBBadSessID æFp DatabaseAccess.p æT CONST æD rcDBBadSessID = -806; æC æKY rcDBBadSessNum æFp DatabaseAccess.p æT CONST æD rcDBBadSessNum = -807; { bad session number for DBGetConnInfo } æC æKY rcDBBadDDEV æFp DatabaseAccess.p æT CONST æD rcDBBadDDEV = -808; { bad ddev specified on DBInit } æC æKY rcDBAsyncNotSupp æFp DatabaseAccess.p æT CONST æD rcDBAsyncNotSupp = -809; { ddev does not support async calls } æC æKY rcDBBadAsyncPB æFp DatabaseAccess.p æT CONST æD rcDBBadAsyncPB = -810; { tried to kill a bad pb } æC æKY rcDBNoHandler æFp DatabaseAccess.p æT CONST æD rcDBNoHandler = -811; { no app handler for specified data type } æC æKY rcDBWrongVersion æFp DatabaseAccess.p æT CONST æD rcDBWrongVersion = -812; { incompatible versions } æC æKY rcDBPackNotInited æFp DatabaseAccess.p æT CONST æD rcDBPackNotInited = -813; { attempt to call other routine before InitDBPack } æC æKY kDBUpdateWind æFp DatabaseAccess.p æT CONST æD { messages for status functions for DBStartQuery } kDBUpdateWind = 0; æC æKY kDBAboutToInit æFp DatabaseAccess.p æT CONST æD kDBAboutToInit = 1; æC æKY kDBInitComplete æFp DatabaseAccess.p æT CONST æD kDBInitComplete = 2; æC æKY kDBSendComplete æFp DatabaseAccess.p æT CONST æD kDBSendComplete = 3; æC æKY kDBExecComplete æFp DatabaseAccess.p æT CONST æD kDBExecComplete = 4; æC æKY kDBStartQueryComplete æFp DatabaseAccess.p æT CONST æD kDBStartQueryComplete = 5; æC æKY kDBGetItemComplete æFp DatabaseAccess.p æT CONST æD { messages for status functions for DBGetQueryResults } kDBGetItemComplete = 6; æC æKY kDBGetQueryResultsComplete æFp DatabaseAccess.p æT CONST æD kDBGetQueryResultsComplete = 7; æC æKY typeNone æFp DatabaseAccess.p æT CONST æD { data type codes } typeNone = 'none'; æC æKY typeBoolean æFp DatabaseAccess.p æT CONST æD typeBoolean = 'bool'; æC æKY typeSMInt æFp DatabaseAccess.p æT CONST æD typeSMInt = 'smin'; æC æKY typeInteger æFp DatabaseAccess.p æT CONST æD typeInteger = 'int '; æC æKY typeSMFloat æFp DatabaseAccess.p æT CONST æD typeSMFloat = 'smfl'; æC æKY typeFloat æFp DatabaseAccess.p æT CONST æD typeFloat = 'flot'; æC æKY typeDate æFp DatabaseAccess.p æT CONST æD typeDate = 'date'; æC æKY typeTime æFp DatabaseAccess.p æT CONST æD typeTime = 'time'; æC æKY typeTimeStamp æFp DatabaseAccess.p æT CONST æD typeTimeStamp = 'tims'; æC æKY typeChar æFp DatabaseAccess.p æT CONST æD typeChar = 'char'; æC æKY typeDecimal æFp DatabaseAccess.p æT CONST æD typeDecimal = 'decm'; æC æKY typeMoney æFp DatabaseAccess.p æT CONST æD typeMoney = 'mony'; æC æKY typeVChar æFp DatabaseAccess.p æT CONST æD typeVChar = 'vchr'; æC æKY typeVBin æFp DatabaseAccess.p æT CONST æD typeVBin = 'vbin'; æC æKY typeLChar æFp DatabaseAccess.p æT CONST æD typeLChar = 'lchr'; æC æKY typeLBin æFp DatabaseAccess.p æT CONST æD typeLBin = 'lbin'; æC æKY typeDiscard æFp DatabaseAccess.p æT CONST æD typeDiscard = 'disc'; æC æKY typeUnknown æFp DatabaseAccess.p æT CONST æD { "dummy" types for DBResultsToText } typeUnknown = 'unkn'; æC æKY typeColBreak æFp DatabaseAccess.p æT CONST æD typeColBreak = 'cbrk'; æC æKY typeRowBreak æFp DatabaseAccess.p æT CONST æD typeRowBreak = 'rbrk'; æC æKY typeAnyType æFp DatabaseAccess.p æT CONST æD { pass this in to DBGetItem for any data type } typeAnyType = 0; æC æKY kDBWaitForever æFp DatabaseAccess.p æT CONST æD { infinite timeout value for DBGetItem } kDBWaitForever = -1; æC æKY kDBLastColFlag æFp DatabaseAccess.p æT CONST æD { flag for last column in row for DBGetItem } kDBLastColFlag = $0001; æC æKY DBAsyncParamBlockRec DBAsyncParmBlkPtr æFp DatabaseAccess.p æT RECORD æD DBAsyncParmBlkPtr = ^DBAsyncParamBlockRec; DBAsyncParamBlockRec = RECORD completionProc: ProcPtr; { pointer to completion routine } result: OSErr; { result of call } userRef: long; { for application's use } ddevRef: long; { for ddev's use } reserved: long; { for internal use } END; { structure for resource list in QueryRecord } æC æKY ResListElem ResListHandle æFp DatabaseAccess.p æT RECORD æD ResListElem = RECORD theType: ResType; { resource type } id: word; { resource id } END; { structure for query list in QueryRecord } æC æKY QueryArray QueryListPtr QueryListHandle æFp DatabaseAccess.p æT RECORD æD QuerListPtr = ^QueryArray; QueryListHandle = ^QuerListPtr; QueryArray = ARRAY [0..255] OF Handle; æC æKY QueryRecord QueryPtr QueryHandle æFp DatabaseAccess.p æT RECORD æD QueryPtr = ^QueryRecord; QueryHandle = ^QueryPtr; QueryRecord = RECORD version: short; { version } id: short; { id of 'qrsc' this came from } queryProc: Handle; { handle to query def proc } ddevName: Str63; { ddev name } host: Str255; { host } user: Str255; { user } password: Str255; { password } connStr: Str255; { connection string } currQuery: short; { current query } numQueries: short; { number of queries in queryList } queryList: QueryListHandle; { handle to list of queries } numRes: short; { number of resources in resList } resList: ResListHandle; { handle to list of other resources } dataHandle: Handle; { data used by query def proc } refCon: long; { query's reference value } END; { structure of column types array in ResultsRecord } æC æKY DBColInfoRecord æFp DatabaseAccess.p æT RECORD æD DBColInfoRecord = RECORD len: word; places: word; flags: word; END; æC æKY ResultsRecord æFp DatabaseAccess.p æT RECORD æD ResultsRecord = RECORD numRows: short; { number of rows in result } numCols: short; { number of colums per row } colTypes: Handle; { data type array} colData: Handle; { actual results } colInfo: Handle; { DBColInfoRecord array } END; æC æKY InitDBPack æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION InitDBPack: OSErr; INLINE $3F3C,$0004,$303C,$0100,$A82F; æDT myVariable := InitDBPack(paramList); æC You must call the InitDBPack function before you call any other Database Access Manager routines. You must call the QuitDBPack function when you are finished using the Database Access Manager. FUNCTION InitDBPack : OSErr; The InitDBPack function causes the Package Manager to load the Database Access Manager into memory, if it has not already done so, and increments the Database Access Manager use counter. The use counter prevents any application from removing the Database Access Manager from memory while another application is using it. The interface routine that implements the InitDBPack function includes a version number for the Database Access Manager. If the package is a different version than specified by the interface routine, then the InitDBPack function returns the rcDBWrongVersion result code. Result codes noErr 0 No error rcDBWrongVersion –814 Wrong version number æKY QuitDBPack æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION QuitDBPack: OSErr; INLINE $303C,$0001,$A82F; æDT myVariable := QuitDBPack(paramList); æC FUNCTION QuitDBPack : OSErr; The QuitDBPack function decrements the Database Access Manager use counter. When this counter equals 0, the QuitDBPack function removes the Database Access Manager package from memory. Call this routine when your application is terminating or when you are finished using the Database Access Manager. The use counter prevents the QuitDBPack function from removing the Database Access Manager from memory while any application is still using it. Result codes noErr 0 No error rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBInit æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBInit(VAR sessID: LONGINT;ddevName: Str63;host: Str255;user: Str255; passwd: Str255;connStr: Str255;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0E02,$A82F; æDT myVariable := DBInit(sessID,ddevName,host,user,passwd,connStr,asyncPB); æC FUNCTION DBInit (VAR sessID: LongInt; ddevName: Str63; host, user, password, connStr: Str255; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBInit function initiates a session with a remote database server. You must initiate a session before you call any Database Access Manager function that requires a session ID as an input parameter. If the DBInit function returns a nonzero session ID, you must call the DBEnd function to terminate the session, even if the DBInit function also returns a result code other than noErr. Because the high-level function DBStartQuery can call the DBInit function, if you have called the DBStartQuery function, you do not have to call the DBInit function. The DBInit function returns the session ID in the sessID parameter. This session ID is unique; no other current session, for any database extension, has the same session ID. You must specify the session ID any time you want to send data to or retrieve data from this session. Depending on the database extension you are using, the DBInit function might return a session ID of 0 if it fails to initiate a session, or it might return a nonzero session ID and a result code other than noErr. In the latter case, you can pass the session ID to the DBGetErr function to determine the cause of the error. The ddevName parameter is a string of no more than 63 characters that specifies the name of the database extension. The name of the database extension is contained in the database extension file in a resource of type 'STR ' with an ID of 128. For the CL/1 database extension provided by Apple , for example, this string is “CL/1”. The host parameter specifies the name of the remote system on which the database server is located. This name depends on the manner in which the database extension establishes communication with the remote database server and on how the system administrator has set up the computer system. The user parameter specifies the name of the user, and the password parameter specifies the password associated with the user name. The connStr parameter is a connection string that is passed to the database server, which might pass it on to the database management software on the remote computer. This string is necessary in some systems to complete log-on procedures. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error rcDBError –802 Error initiating session rcDBBadDDev –809 Couldn’t find specified database extension or trouble opening ddev file rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBEnd æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBEnd(sessID: LONGINT;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0403,$A82F; æDT myVariable := DBEnd(sessID,asyncPB); æC FUNCTION DBEnd (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBEnd function terminates a session with a remote database server and terminates the network connection between the application and the remote computer. You must call the DBEnd function to terminate a session. The sessID parameter is the session ID that was returned by the DBInit function. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error rcDBError –802 Error ending session rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBGetConnInfo æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBGetConnInfo(sessID: long;sessNum: short;VAR returnID: long;version: long; VAR ddevName: Str63;VAR host: Str255;VAR user: Str255;VAR network: Str255; VAR connStr: Str255;VAR start: long;VAR state: OSErr;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$1704,$A82F; æDT myVariable := DBGetConnInfo(sessID,sessNum,returnID,version,ddevName,host,user,network,connStr,start,state,asyncPB); æC FUNCTION DBGetConnInfo (sessID: LongInt; sessNum: Integer; VAR returnedID, version: LongInt; VAR ddevName: Str63; VAR host, user, network, connStr: Str255; VAR start: LongInt; VAR state: OSErr; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBGetConnInfo function returns information about the specified session, including • the version of the database extension • the name of the remote system on which the session is running • the user name • the connection string that was used to establish communication • the name of the network • the time at which the session started, in ticks • the status of the session In addition, if you include a nonzero value for the sessID parameter when you call the DBGetConnInfo function, the function returns the name of the database extension. If you use 0 for the sessID parameter and specify the database extension and session number instead, the function returns the session ID. You can use this function to get information about a particular session, or you can call the function repeatedly, incrementing the session number each time, to get information about all of the sessions associated with a particular database extension. The sessID parameter is the session ID that was returned by the DBInit function. The sessNum parameter is the session number of the session about which you want information. You can specify either the session ID or the session number when you call the DBInit function. If you specify the sessID parameter, use 0 for the sessNum parameter. If you specify the sessNum parameter, then use 0 for the sessID parameter. If you specify the sessNum parameter, you must specify a value for the ddevName parameter as well. If you specify the session number and the database extension, then the DBGetConnInfo function returns the session ID in the returnedID parameter. The version parameter returns the version number of the database extension that is the interface to the remote database server on which this session is running. The ddevName parameter specifies the name of the database extension. If you specify 0 for the session ID, you must include the name of the database extension as well as a session number. If you specify a valid session ID, then the DBGetConnInfo function returns the name of the database extension in the ddevName parameter. The name of the database extension is included in a 'STR ' resource in the database extension file with a resource ID of 128. The host, user, and connStr parameters are the host, user, and connection strings that were used to establish communication with the remote database server. The network parameter is the name of the network through which your computer is communicating with the remote database server. The start parameter is the time, in ticks, at which this session was initiated. The state parameter returns one of the following values to provide information about the status of the session: CONST noErr = 0 ;No error; ready for more text rcDBValue = –801 ;Output data available rcDBError = –802 ;Execution ended in an error rcDBExec = –806 ;Busy; currently executing query The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error rcDBBadSessNum –808 Invalid session number rcDBBadSessID –807 Session ID is invalid or database extension name is invalid rcDBBadDDev –809 Couldn’t find specified database extension or trouble opening ddev file rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBGetSessionNum æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBGetSessionNum(sessID: LONGINT;VAR sessNum: INTEGER;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0605,$A82F; æDT myVariable := DBGetSessionNum(sessID,sessNum,asyncPB); æC FUNCTION DBGetSessionNum (sessID: LongInt; VAR sessNum: Integer; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBGetSessionNum function returns the session number of the session you specify with the session ID parameter. The session number is unique for a particular database extension, but the same session number might be in use for different database extensions at the same time. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBSend æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBSend(sessID: LONGINT;text: Ptr;len: INTEGER;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0706,$A82F; æDT myVariable := DBSend(sessID,text,len,asyncPB); æC FUNCTION DBSend (sessID: LongInt; text: Ptr; len: Integer; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBSend function sends a query or a portion of a query to the remote database server. The database server appends this portion of the query to any portion you sent previously. Because the Database Access Manager and database server do not modify the string you send in any way, they do not insert any delimiter between fragments of queries that you send to the database server. If you want a blank or a semicolon to be included between query fragments, or if you want to use return characters to divide the query into lines of text, you must include them in the character string that you send with this function. The database server does not execute the query until you call the DBExec function. The sessID parameter is the session ID that was returned by the DBInit function. The text parameter is a pointer to the query or query fragment that you want to send to the database server. The query or query fragment must be a character string. The len parameter specifies the length of the character string. If the len parameter has a value of –1, then the character string is assumed to be “NULL terminated” (that is, the string ends with a NULL byte); otherwise, the len parameter specifies the number of bytes in the string. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error rcDBError –802 Error trying to send text rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBSendItem æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBSendItem(sessID: LONGINT;dataType: DBType;len: INTEGER;places: INTEGER; flags: INTEGER;buffer: Ptr;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0B07,$A82F; æDT myVariable := DBSendItem(sessID,dataType,len,places,flags,buffer,asyncPB); æC FUNCTION DBSendItem (sessID: LongInt; dataType: DBType; len, places, flags: Integer; buffer: Ptr; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBSendItem function sends a single data item to the remote database server. You can use this function to send to the database server the data that you wish to include in a query. The database extension or the database server (depending on how the system is implemented) converts the data item to a character string and appends it to the query, just as a query program fragment is appended to the query by the DBSend function. The query is not executed until you call the DBExec function. The sessID parameter is the session ID that was returned by the DBInit function. The dataType, len, and places parameters specify the data type, length, and number of decimal places for the data item that you are sending to the remote database server. The database extension and database server ignore the len parameter if the data type has an implied length. The database extension and database server ignore the places parameter for all values of the dataType parameter except typeDecimal and typeMoney. Data types are discussed in “Getting Query Results” earlier in this chapter. The buffer parameter is a pointer to the memory location of the data item that you want to send. When you use the DBSendItem function to send an item of data to a database server, the database extension and database server format the data according to the data type, length, and decimal places you specified, converts it to a character string, and appends the data to the query. Set the flags parameter to 0. There are no flags currently defined for the DBSendItem function. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error rcDBError –802 Error trying to send item rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBExec æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBExec(sessID: LONGINT;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0408,$A82F; æDT myVariable := DBExec(sessID,asyncPB); æC FUNCTION DBExec (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBExec function initiates execution of a query that you have sent to the remote database server. Use the DBSend and DBSendItem functions to send a query to the database server. Use the DBState function to determine the status of a query after you have initiated execution. The sessID parameter is the session ID that was returned by the DBInit function. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 Execution has begun rcDBError –802 Error trying to begin execution rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBState æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBState(sessID: LONGINT;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0409,$A82F; æDT myVariable := DBState(sessID,asyncPB); æC FUNCTION DBState (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr; The result code returned by the DBState function indicates the status of the remote database server. You can use this function to determine whether the database server has successfully executed a query and whether it has data available for you to retrieve. The sessID parameter is the session ID that was returned by the DBInit function. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error; ready for more text rcDBValue –801 Output data available rcDBError –802 Execution ended in an error rcDBExec –806 Currently executing query rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBGetErr æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBGetErr(sessID: long;VAR err1: long;VAR err2: long;VAR item1: Str255; VAR item2: Str255;VAR errorMsg: Str255;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0E0A,$A82F; æDT myVariable := DBGetErr(sessID,err1,err2,item1,item2,errorMsg,asyncPB); æC FUNCTION DBGetErr (sessID: LongInt; VAR err1,err2: LongInt; VAR item1, item2, errorMsg: Str255; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBGetErr function retrieves error codes and error messages from a remote database server. You can use this function to obtain information when a low-level function returns the result code rcDBError. If the DBState function returns the rcDBError result code, indicating that execution of a query ended in an error, the error information can help you debug the query. The meaning of each error code and error message returned by this function depends on the database server with which you are communicating; see the documentation for that database server for more information. The sessID parameter is the session ID that was returned by the DBInit function. The err1 and err2 parameters return the primary and secondary error codes. The item1 and item2 parameters return strings that describe the objects of the error message. The errorMsg parameter returns the error message. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error rcDBError –802 Error retrieving error information rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBBreak æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBBreak(sessID: LONGINT;abort: BOOLEAN;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$050B,$A82F; æDT myVariable := DBBreak(sessID,abort,asyncPB); æC FUNCTION DBBreak (sessID: LongInt; abort: Boolean; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBBreak function can halt execution of a query and reinitialize the remote database server, or it can unconditionally terminate a session with a database server. You can use this function to cancel a query if you determine that it is taking too long to complete execution, for example. The sessID parameter is the session ID that was returned by the DBInit function. If the abort parameter is TRUE (nonzero), the database server halts any query that is executing and terminates the current session. If the abort parameter is FALSE (0), the database server halts any query that is executing and reinitializes itself. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 Execution has begun rcDBError –802 Break or abort attempt was unsuccessful rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBGetItem æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBGetItem(sessID: LONGINT;timeout: LONGINT;VAR dataType: Byte; VAR len: sort;VAR places: INTEGER;VAR flags: INTEGER;buffer: Ptr;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$100C,$A82F; æDT myVariable := DBGetItem(sessID,timeout,dataType,len,places,flags,buffer,asyncPB); æC FUNCTION DBGetItem (sessID: LongInt; timeout: LongInt; VAR dataType: DBType; VAR len,places,flags: Integer; buffer: Ptr; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBGetItem function retrieves the next data item from the database server. You can also use this function to obtain information about the next data item without retrieving the data. You can use the DBGetItem function after you have executed a query and the DBState function has returned the result code rcDBValue, indicating that data is available. You can repeat the DBGetItem function as many times as is necessary to retrieve all of the data returned by the database in response to a query. The sessID parameter is the session ID that was returned by the DBInit function. You can use the timeout parameter to specify the maximum amount of time that the database extension should wait to receive results from the database server before canceling the function. Specify the timeout parameter in sixtieths of a second. To disable the timeout feature, set the timeout parameter to the value kDBWaitForever. If the timeout period expires, the DBGetItem function returns the result code rcDBBreak. The DBGetItem function ignores the timeout parameter if you call the function asynchronously. One use for the timeout parameter is to call the DBGetItem function periodically with a short value set for this parameter in order to return control to your application while a query is executing. Your application can then retrieve the next data item as soon as execution of the query is complete without having to call the DBState function to determine when data is available. You can set the dataType parameter to specify the data type that you expect the next data item to be. If the item is not of the expected data type, the database extension returns the rcDBBadType result code. If you want to retrieve the next data item regardless of type, set the dataType parameter to the value typeAnyType. To skip the next data item, set the dataType parameter to the value typeDiscard. The database server sets the dataType parameter to the actual type of the data item when it retrieves the data item or returns information about the data item. Data types are discussed in “Getting Query Results” earlier in this chapter. Set the len parameter to the length of the data buffer pointed to by the buffer parameter. If you use the DBGetItem function to obtain information only (by setting the buffer parameter to NIL), then the database server ignores the len parameter. The database server sets the len parameter to the actual length of the data item when it retrieves the data item or returns information about the data item. The database server returns in the places parameter the number of decimal places in data items of types typeMoney and typeDecimal. For all other data types, the database server returns 0 for the places parameter. The buffer parameter is a pointer to the location where you want the retrieved data item to be stored. You must ensure that the location you specify contains enough space for the data item that will be returned. To determine the data type, length, and number of decimal places of the next data item without retrieving it, specify NIL for the buffer parameter. If the flags parameter is set to kDBLastColFlag (that is, the least significant bit is set to 1), the data item is in the last column of the row. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error; no next data item rcDBNull –800 The data item was NULL rcDBValue –801 A nonzero data item was successfully retrieved rcDBError –802 Execution ended in an error rcDBBadType –803 Next data item not of requested data type rcDBBreak –805 Timed out rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBUnGetItem æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBUnGetItem(sessID: LONGINT;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$040D,$A82F; æDT myVariable := DBUnGetItem(sessID,asyncPB); æC FUNCTION DBUnGetItem (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBUnGetItem function reverses the effect of the last call to the DBGetItem function, in the sense that the next time you call the DBGetItem function it retrieves the same item a second time. It does not remove the just-retrieved data item from the input buffer. The DBUnGetItem function can reverse the effect of only one call to the DBGetItem function; you cannot use it to step back through several previously retrieved data items. The sessID parameter is the session ID that was returned by the DBInit function. The asyncPB parameter is a pointer to the asynchronous parameter block. If you do not want to call the function asynchronously, set this parameter to NIL. Result codes noErr 0 No error rcDBError –802 Error executing function rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 Asynchronous calls are not supported by database extension rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBKill æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBKill(asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$020E,$A82F; æDT myVariable := DBKill(asyncPB); æC FUNCTION DBKill (asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBKill function cancels the execution of the asynchronous call specified by the asyncPB parameter. The asyncPB parameter is a pointer to the asynchronous parameter block. Result codes noErr 0 Asynchronous routine canceled successfully rcDBError –802 Error canceling routine rcDBBadAsynchPB –812 Invalid parameter block specified rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBGetNewQuery æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBGetNewQuery(queryID: INTEGER;VAR qeury: QueryHandle): OSErr; INLINE $303C,$030F,$A82F; æDT myVariable := DBGetNewQuery(queryID,qeury); æC FUNCTION DBGetNewQuery (queryID: Integer; VAR query: QueryHandle) : OSErr; The DBGetNewQuery function creates a query record from the 'qrsc' resource with the resource ID you specify in the queryID parameter. The resource file that contains the 'qrsc' resource must remain open until after the DBStartQuery function has completed execution. If you do not already know the resource ID of the 'qrsc' resource (for example, if you call the SFGetFile procedure to let the user select the query document), you can use Resource Manager routines to determine the resource ID. The SFGetFile procedure is described in the Standard File Package chapter of Volume I and the Resource Manager is described in Volume Chapter 5. The queryID parameter specifies the resource ID of the 'qrsc' resource that you want to use. The query parameter returns a handle to the query record. Result code noErr 0 Query record built successfully rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBDisposeQuery æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBDisposeQuery(query: QueryHandle): OSErr; INLINE $303C,$0210,$A82F; æDT myVariable := DBDisposeQuery(query); æC FUNCTION DBDisposeQuery (query: QueryHandle) : OSErr; The DBDisposeQuery function disposes of a query record and frees all the memory that the Database Access Manager allocated when it created the query record. You should call this function after you are finished using a query record. The query parameter is a handle to the query record. Result code noErr 0 Query record disposed of successfully rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBStartQuery æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBStartQuery(VAR sessID: long;query: QueryHandle;statusProc: ProcPtr; asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0811,$A82F; æDT myVariable := DBStartQuery(sessID,query,statusProc,asyncPB); æC FUNCTION DBStartQuery (VAR sessID: LongInt; query: QueryHandle; statusProc: ProcPtr; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBStartQuery function performs the following tasks, in the order specified: 1. It calls the query definition function (if any) pointed to by the query record. The query definition function modifies the query record and the query, usually by asking the user for input. The query definition function can display a dialog box that gives the user the option of canceling the query; if the user does cancel the query, the DBStartQuery function returns the userCanceledErr result code. 2. If you specify a nonzero value for the statusProc parameter, the DBStartQuery function calls your status routine with the value kDBUpdateWind in the message parameter so that your application can update its windows. 3. If you specify a nonzero value for the statusProc parameter, the DBStartQuery function calls your status routine with the value kDBAboutToInit in the message parameter so that your application can display a dialog box informing the user that a database session is about to be established, and giving the user the option of canceling execution of the function. 4. If the sessID parameter is 0, the DBStartQuery function calls the DBInit function to establish a database session, and returns a session ID. 5. If you specify a nonzero value for the statusProc parameter and the DBStartQuery function called the DBInit function, the DBStartQuery function calls your status routine with the value kDBInitComplete in the message parameter and the result of the DBInit function in the result parameter. 6. The DBStartQuery function calls the DBSend function to send the query to the remote database server. 7. If you specify a nonzero value for the statusProc parameter, the DBStartQuery function calls your status routine with the value kDBSendComplete in the message parameter and the result of the DBSend function in the result parameter. 8. The DBStartQuery function calls the DBExec function to execute the query. 9. If you specify a nonzero value for the statusProc parameter, the DBStartQuery function calls your status routine with the value kDBExecComplete in the message parameter and the result of the DBExec function in the result parameter. 10. If you specify a nonzero value for the statusProc parameter, the DBStartQuery function calls your status routine with the value kDBStartQueryComplete in the message parameter and the result of the DBStartQuery function in the result parameter. You can use the sessID parameter to specify a session ID if your application or another application has already established a session with the database server. If you specify NIL for this parameter, then the DBStartQuery function establishes a session and returns the session ID in the sessID parameter. You use the query parameter to specify a handle to a query record. You can use the statusProc pointer to specify a pointer to a status routine that your application can use to update its windows after the query definition function has completed execution. If you specify NIL for this parameter, the DBStartQuery function does not attempt to update your application’s windows. The DBStartQuery function also calls your status routine before it initiates a database session, after it calls the DBInit function, after it calls the DBSend function, and after it calls the DBExec function. Status routines are discussed in “Writing a Status Routine for High-Level Functions” earlier in this chapter. If you specify a pointer to an asynchronous parameter block in the asyncPB parameter, the DBStartQuery function calls the DBInit, DBSend, and DBExec functions asynchronously. As soon as the DBInit function has started execution, it returns control to your application. Your application must then call the WaitNextEvent routine periodically to allow these asynchronous routines to run, and it must check the result field of the asynchronous parameter block to determine when each routine has completed execution. Result codes noErr 0 No error userCanceledErr –128 User canceled the query rcDBError –802 Error initiating session, sending text, or executing query rcDBBadDDev –809 Couldn’t find the specified database extension, or error occurred in opening database extension rcDBAsyncNotSupp –811 The database extension does not support asynchronous calls rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBGetQueryResults æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBGetQueryResults(sessID: LONGINT;VAR results: ResultsRecord;timeout: LONGINT; statusProc: ProcPtr;asyncPB: DBAsyncParmBlkPtr): OSErr; INLINE $303C,$0A12,$A82F; æDT myVariable := DBGetQueryResults(sessID,results,timeout,statusProc,asyncPB); æC FUNCTION DBGetQueryResults (sessID: LongInt; VAR results: ResultsRecord; timeout: LongInt; statusProc: ProcPtr; asyncPB: DBAsyncParmBlkPtr) : OSErr; The DBGetQueryResults function retrieves the results returned by a query and places them in memory. If there is sufficient memory available, this function retrieves all of the results at once. If the DBGetQueryResults function runs out of memory, it places as much data as possible in memory, up to the last whole row. You can then make more memory available and call the DBGetQueryResults function again to retrieve more data. The DBGetQueryResults function can be used to retrieve the results of any query, not only queries sent and executed by the DBStartQuery function. The sessID parameter specifies the ID of the session from which you wish to retrieve results. The results parameter is the results record, which contains a handle to the retrieved data. Results records are described in “Getting Query Results” earlier in this chapter. The timeout parameter specifies the value that he DBGetQueryResults uses for the timeout parameter each time it calls the DBGetItem function. The timeout parameter specifies the maximum amount of time that the database extension should wait to receive results from the database server before canceling the DBGetItem function. Specify the timeout parameter in sixtieths of a second. To disable the timeout feature, set the timeout parameter to the value kDBWaitForever. This parameter is ignored if you specify a nonzero value for the asyncPB parameter. You can use the statusProc pointer to specify a pointer to a status routine that you provide. The DBGetQueryResults function calls your status routine after it calls the DBGetItem function to retrieve a data item. When it calls the status routine, the DBGetQueryResults function provides the results of the DBGetItem function, the data type, the data length, number of decimal places, and flags associated with the data item, and a pointer to the data item. Status routines are discussed in “Writing a Status Routine For High-Level Functions” earlier in this chapter. If you specify a pointer to an asynchronous parameter block in the asyncPB parameter, the DBGetQueryResults function calls the DBGetItem function asynchronously for each data item. As soon as the DBGetItem function has started execution, it returns control to your application. Your application must then call the WaitNextEvent routine periodically to allow this asynchronous routine to run, and it must check the result field of the asynchronous parameter block to determine when the routine has completed execution. Result codes noErr 0 Query execution successful; no results returned userCanceledErr –128 Function canceled by status routine rcDBValue –801 Data available rcDBError –802 Query execution ended in an error rcDBBreak –805 Function timed out rcDBExec –806 Query currently executing rcDBBadSessID –807 Session ID is invalid rcDBAsyncNotSupp –811 The database extension does not support asynchronous calls rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBResultsToText æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBResultsToText(results: ResultsRecord;VAR theText: Handle): OSErr; INLINE $303C,$0413,$A82F; æDT myVariable := DBResultsToText(results,theText); æC FUNCTION DBResultsToText (results: ResultsRecord; VAR theText: Handle) : OSErr; The DBResultsToText function calls result handlers to convert to text the data retrieved by the DBGetQueryResults function. Result handlers are described in “Converting Query Results to Text” earlier in this chapter. The results parameter is the results record returned by the DBGetQueryResults function. The parameter theText contains a handle to the converted text. This handle is allocated by the Database Access Manager. Result code noErr 0 No error rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBInstallResultHandler æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBInstallResultHandler(dataType: DBType;theHandler: ProcPtr;isSysHandler: BOOLEAN): OSErr; INLINE $303C,$0514,$A82F; æDT myVariable := DBInstallResultHandler(dataType,theHandler,isSysHandler); æC FUNCTION DBInstallResultHandler (dataType: DBType; theHandler: ProcPtr; isSysHandler: Boolean) : OSErr; The DBInstallResultHandler function installs a result handler for the data type specified by the dataType parameter. The result handler is then used by the DBResultsToText function to convert data of the specified type into a character string. The parameter theHandler is a pointer to the result handler. The isSysHandler parameter specifies whether the result handler is an application result handler—to be used only when the DBResultsToText function is called by the application that installed the result handler—or a system result handler—to be used by every application running on the system. When you install an application result handler, it replaces any result handler with the same name previously installed by that application. Similarly, when you install a system result handler, it replaces any existing system result handler with the same name. Before you temporarily replace an existing result handler, use the DBGetResultHandler function to obtain a pointer to the present handler, and save the present result handler in your application’s private storage. Then you can reinstall the original result handler when you are finished using the temporary one. Because an application result handler is used in preference to a system result handler if both are available, you can temporarily replace a system result handler for purposes of your application by installing an application result handler for the same data type. You can then use the DBRemoveResultHandler function to remove the application result handler and return to using the system result handler whenever you wish. Result code noErr 0 No error rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBRemoveResultHandler æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBRemoveResultHandler(dataType: DBType): OSErr; INLINE $303C,$0215,$A82F; æDT myVariable := DBRemoveResultHandler(dataType); æC FUNCTION DBRemoveResultHandler (dataType: DBType) : OSErr; The DBRemoveResultHandler function removes from memory the application result handler for the data type that you specify with the dataType parameter. This function cannot remove a system result handler. Result codes noErr 0 No error rcDBNoHandler –813 There is no handler for this data type installed for the current application rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DBGetResultHandler æFp DatabaseAccess.p æT FUNCTION æTN A82F æD FUNCTION DBGetResultHandler(dataType: DBType;VAR theHandler: ProcPtr;getSysHandler: BOOLEAN): OSErr; INLINE $303C,$0516,$A82F; æDT myVariable := DBGetResultHandler(dataType,theHandler,getSysHandler); æC FUNCTION DBInstallResultHandler (dataType: DBType; theHandler: ProcPtr; isSysHandler: Boolean) : OSErr; The DBInstallResultHandler function installs a result handler for the data type specified by the dataType parameter. The result handler is then used by the DBResultsToText function to convert data of the specified type into a character string. The parameter theHandler is a pointer to the result handler. The isSysHandler parameter specifies whether the result handler is an application result handler—to be used only when the DBResultsToText function is called by the application that installed the result handler—or a system result handler—to be used by every application running on the system. When you install an application result handler, it replaces any result handler with the same name previously installed by that application. Similarly, when you install a system result handler, it replaces any existing system result handler with the same name. Before you temporarily replace an existing result handler, use the DBGetResultHandler function to obtain a pointer to the present handler, and save the present result handler in your application’s private storage. Then you can reinstall the original result handler when you are finished using the temporary one. Because an application result handler is used in preference to a system result handler if both are available, you can temporarily replace a system result handler for purposes of your application by installing an application result handler for the same data type. You can then use the DBRemoveResultHandler function to remove the application result handler and return to using the system result handler whenever you wish. Result code noErr 0 No error rcDBPackNotInited –815 The InitDBPack function has not yet been called æKY DDEV.p æKL DDEVFlags DDEVParams DDEVParamsPtr kAsyncSupported kDBBreak kDBClose kDBEnd kDBExec kDBGetConnInfo kDBGetErr kDBGetItem kDBGetSessionNum kDBIdle kDBInit kDBKill kDBOpen kDBSend kDBSendItem kDBState kDBUnGetItem kDDEVFlags kDDEVID kDDEVName æKY kDBInit æFp DDEV.p æT CONST æD { messages for ddev } kDBInit = 0; æC æKY kDBEnd æFp DDEV.p æT CONST æD kDBEnd = 1; æC æKY kDBGetConnInfo æFp DDEV.p æT CONST æD kDBGetConnInfo = 2; æC æKY kDBGetSessionNum æFp DDEV.p æT CONST æD kDBGetSessionNum = 3; æC æKY kDBSend æFp DDEV.p æT CONST æD kDBSend = 4; æC æKY kDBSendItem æFp DDEV.p æT CONST æD kDBSendItem = 5; æC æKY kDBExec æFp DDEV.p æT CONST æD kDBExec = 6; æC æKY kDBState æFp DDEV.p æT CONST æD kDBState = 7; æC æKY kDBGetErr æFp DDEV.p æT CONST æD kDBGetErr = 8; æC æKY kDBBreak æFp DDEV.p æT CONST æD kDBBreak = 9; æC æKY kDBGetItem æFp DDEV.p æT CONST æD kDBGetItem = 10; æC æKY kDBUnGetItem æFp DDEV.p æT CONST æD kDBUnGetItem = 11; æC æKY kDBKill æFp DDEV.p æT CONST æD kDBKill = 12; æC æKY kDBOpen æFp DDEV.p æT CONST æD kDBOpen = 100; æC æKY kDBClose æFp DDEV.p æT CONST æD kDBClose = 101; æC æKY kDBIdle æFp DDEV.p æT CONST æD kDBIdle = 102; æC æKY kDDEVName æFp DDEV.p æT CONST æD { resource IDs of misc. resources } kDDEVName = 128; { ID of 'STR ' resource with ddev name } æC æKY kDDEVID æFp DDEV.p æT CONST æD kDDEVID = 128; { ID of 'ddev' resource } æC æKY kDDEVFlags æFp DDEV.p æT CONST æD kDDEVFlags = 128; { ID of 'dflg' resource } æC æKY kAsyncSupported æFp DDEV.p æT CONST æD kAsyncSupported = $00000001; { bit for async support } æC æKY DDEVFlags æFp DDEV.p æT RECORD æD DDEVFlags = RECORD version: LONGINT; { always 0 for this release } flags: LONGINT; { flags } END; æC æKY DDEVParams DDEVParamsPtr æFp DDEV.p æT RECORD æD DDEVParamsPtr = ^DDEVParams; DDEVParams = RECORD message: INTEGER; { action for ddev } ddevStorage: LONGINT; { storage for ddev } asyncPB: DBAsyncParmBlkPtr; { async parameter block pointer } sessID: LONGINT; { session ID } returnedID: LONGINT; { session ID returned by DBGetConnInfo } version: LONGINT; { version returned by DBGetConnInfo } start: LONGINT; { start returned by DBGetConnInfo } host: StringPtr; { host for DBInit and DBGetConnInfo } user: StringPtr; { user for DBInit and DBGetConnInfo } password: StringPtr; { password for DBInit and DBGetConnInfo } connStr: StringPtr; { connection string for DBInit and DBGetConnInfo } network: StringPtr; { network for DBInit and DBGetConnInfo } buffer: Ptr; { buffer used in several calls } err1: LONGINT; { error 1 for DGGetErr } err2: LONGINT; { error 2 for DGGetErr } item1: StringPtr; { item 1 for DGGetErr } item2: StringPtr; { item 2 for DGGetErr } errorMsg: StringPtr; { errorMsg for DGGetErr } timeout: LONGINT; { timeout for DGGetItem} dataType: DBType; { type for several calls } sessNum: INTEGER; { session number for DBGetConnInfo and DBGetSessionNum} state: INTEGER; { state for DBGetConnInfo } len: INTEGER; { length of buffer } places: INTEGER; { places for DBSendItem and DBGetItem } flags: INTEGER; { flags for DBSendItem and DBGetItem } abort: BOOLEAN; { abort for DBBreak } END; æC æKY Desk.p æKL CloseDeskAcc OpenDeskAcc SystemClick SystemEdit SystemEvent SystemMenu SystemTask accClear accCopy accCursor accCut accEvent accMenu accPaste accRun accUndo goodbye æKY accEvent æFp Desk.p æT CONST æD accEvent = 64; æC æKY accRun æFp Desk.p æT CONST æD accRun = 65; æC æKY accCursor æFp Desk.p æT CONST æD accCursor = 66; æC æKY accMenu æFp Desk.p æT CONST æD accMenu = 67; æC æKY accUndo æFp Desk.p æT CONST æD accUndo = 68; æC æKY accCut æFp Desk.p æT CONST æD accCut = 70; æC æKY accCopy æFp Desk.p æT CONST æD accCopy = 71; æC æKY accPaste æFp Desk.p æT CONST æD accPaste = 72; æC æKY accClear æFp Desk.p æT CONST æD accClear = 73; æC æKY goodbye æFp Desk.p æT CONST æD goodbye = -1; {goodbye message} æC æKY OpenDeskAcc æFp Desk.p æT FUNCTION æTN A9B6 æD FUNCTION OpenDeskAcc(theAcc: Str255): INTEGER; INLINE $A9B6; æDT myVariable := OpenDeskAcc(theAcc); æMM æRI I-440 æC OpenDeskAcc opens the desk accessory having the given name and displays its window (if any) as the active window. The name is the accessory’s resource name, which you get from the Apple menu by calling the Menu Manager procedure GetItem. OpenDeskAcc calls the Resource Manager to read the desk accessory from the resource file into the application heap. You should ignore the value returned by OpenDeskAcc. If the desk accessory is successfully opened, the function result is its driver reference number. However, if the desk accessory can’t be opened, the function result is undefined; the accessory will have taken care of informing the user of the problem (such as memory full) and won’t display itself. Warning: Early versions of some desk accessories may set the current grafPort to the accessory’s port upon return from OpenDeskAcc. To be safe, you should bracket your call to OpenDeskAcc with calls to the QuickDraw procedures GetPort and SetPort, to save and restore the current port. Note: Programmers concerned about the amount of available memory should be aware that an open desk accessory uses from 1K to 3K bytes of heap space in addition to the space needed for the accessory itself. The desk accessory is responsible for determining whether there is sufficient memory for it to run; this can be done by calling SizeResource followed by ResrvMem. æKY CloseDeskAcc æFp Desk.p æT PROCEDURE æTN A9B7 æD PROCEDURE CloseDeskAcc(refNum: INTEGER); INLINE $A9B7; æDT CloseDeskAcc(refNum); æRI I-440 æC When a system window is active and the user chooses Close from the File menu, call CloseDeskAcc to close the desk accessory. RefNum is the driver reference number for the desk accessory, which you get from the windowKind field of its window. The Desk Manager automatically closes a desk accessory if the user clicks its close box. Also, since the application heap is released when the application terminates, every desk accessory goes away at that time. æKY SystemClick æFp Desk.p æT PROCEDURE æTN A9B3 æD PROCEDURE SystemClick(theEvent: EventRecord;theWindow: WindowPtr); INLINE $A9B3; æDT SystemClick(theEvent,theWindow); æMM æRI I-441, P-35, 182 æC When a mouse-down event occurs and the Window Manager function FindWindow reports that the mouse button was pressed in a system window, the application should call SystemClick with the event record and the window pointer. If the given window belongs to a desk accessory, SystemClick sees that the event gets handled properly. SystemClick determines which part of the desk accessory’s window the mouse button was pressed in, and responds accordingly (similar to the way your application responds to mouse activities in its own windows). • If the mouse button was pressed in the content region of the window and the window was active, SystemClick sends the mouse-down event to the desk accessory, which processes it as appropriate. • If the mouse button was pressed in the content region and the window was inactive, SystemClick makes it the active window. • If the mouse button was pressed in the drag region, SystemClick calls the Window Manager procedure DragWindow to pull an outline of the window across the screen and move the window to a new location. If the window was inactive, DragWindow also makes it the active window (unless the Command key was pressed along with the mouse button). • If the mouse button was pressed in the go-away region, SystemClick calls the Window Manager function TrackGoAway to determine whether the mouse is still inside the go-away region when the click is completed: If so, it tells the desk accessory to close itself; otherwise, it does nothing. æKY SystemEdit æFp Desk.p æT FUNCTION æTN A9C2 æD FUNCTION SystemEdit(editCmd: INTEGER): BOOLEAN; INLINE $A9C2; æDT myVariable := SystemEdit(editCmd); æMM æRT 180, 215 æRI I-441 æC Assembly-language note: The macro you invoke to call SystemEdit from assembly language is named _SysEdit. Call SystemEdit when there’s a mouse-down event in the menu bar and the user chooses one of the five standard editing commands from the Edit menu. Pass one of the following as the value of the editCmd parameter: editCmd Editing command 0 Undo 2 Cut 3 Copy 4 Paste 5 Clear If your Edit menu contains these five commands in the standard arrangement (the order listed above, with a dividing line between Undo and Cut), you can simply call SystemEdit(menuItem-1) where menuItem is the menu item number. If the active window doesn’t belong to a desk accessory, SystemEdit returns FALSE; the application should then process the editing command as usual. If the active window does belong to a desk accessory, SystemEdit asks that accessory to process the command and returns TRUE; in this case, the application should ignore the command. Note: It’s up to the application to make sure desk accessories get their editing commands that are chosen from the Edit menu. In particular, make sure your application hasn’t disabled the Edit menu or any of the five standard commands when a desk accessory is activated. æKY SystemTask æFp Desk.p æT PROCEDURE æTN A9B4 æD PROCEDURE SystemTask; INLINE $A9B4; æDT SystemTask(paramList); æRT 85 æRI I-442, 444, II-189, N85-1 æC For each open desk accessory (or other device driver performing periodic actions), SystemTask causes the accessory to perform the periodic action defined for it, if any such action has been defined and if the proper time period has passed since the action was last performed. For example, a clock accessory can be defined such that the second hand is to move once every second; the periodic action for the accessory will be to move the second hand to the next position, and SystemTask will alert the accessory every second to perform that action. You should call SystemTask as often as possible, usually once every time through your main event loop. Call it more than once if your application does an unusually large amount of processing each time through the loop. Note: SystemTask should be called at least every sixtieth of a second. æKY SystemEvent æFp Desk.p æT FUNCTION æTN A9B2 æD FUNCTION SystemEvent(theEvent: EventRecord): BOOLEAN; INLINE $A9B2; æDT myVariable := SystemEvent(theEvent); æRT 5,85 æRI I-442, N5-1, N85-1 æC SystemEvent is called only by the Toolbox Event Manager function GetNextEvent when it receives an event, to determine whether the event should be handled by the application or by the system. If the given event should be handled by the application, SystemEvent returns FALSE; otherwise, it calls the appropriate system code to handle the event and returns TRUE. In the case of a null or mouse-down event, SystemEvent does nothing but return FALSE. Notice that it responds this way to a mouse-down event even though the event may in fact have occurred in a system window (and therefore may have to be handled by the system). The reason for this is that the check for exactly where the event occurred (via the Window Manager function FindWindow) is made later by the application and so would be made twice if SystemEvent were also to do it. To avoid this duplication, SystemEvent passes the event on to the application and lets it make the sole call to FindWindow. Should FindWindow reveal that the mouse-down event did occur in a system window, the application can then call SystemClick, as described above, to get the system to handle it. If the given event is a mouse-up or any keyboard event (including keyboard equivalents of commands), SystemEvent checks whether the active window belongs to a desk accessory and whether that accessory can handle this type of event. If so, it sends the event to the desk accessory and returns TRUE; otherwise, it returns FALSE. If SystemEvent is passed an activate or update event, it checks whether the window the event occurred in is a system window belonging to a desk accessory and whether that accessory can handle this type of event. If so, it sends the event to the desk accessory and returns TRUE; otherwise, it returns FALSE. Note: It’s unlikely that a desk accessory would not be set up to handle keyboard, activate, and update events, or that it would handle mouse-up events. If the given event is a disk-inserted event, SystemEvent does some low-level processing (by calling the File Manager function MountVol) but passes the event on to the application by returning FALSE, in case the application wants to do further processing. Finally, SystemEvent returns FALSE for network, device driver, and application-defined events. Assembly-language note: Advanced programmers can make SystemEvent always return FALSE by setting the global variable SEvtEnb (a byte) to 0. æKY SystemMenu æFp Desk.p æT PROCEDURE æTN A9B5 æD PROCEDURE SystemMenu(menuResult: LONGINT); INLINE $A9B5; æDT SystemMenu(menuResult); æMM æRI I-443 æC SystemMenu is called only by the Menu Manager functions MenuSelect and MenuKey, when an item in a menu belonging to a desk accessory has been chosen. The menuResult parameter has the same format as the value returned by MenuSelect and MenuKey: the menu ID in the high-order word and the menu item number in the low-order word. (The menu ID will be negative.) SystemMenu directs the desk accessory to perform the appropriate action for the given menu item. æKY DeskBus.p æKL ADBOp ADBReInit CountADBs GetADBInfo GetIndADB SetADBInfo ADBAddress ADBDataBlock ADBDBlkPtr ADBOpBlock ADBOpBPtr ADBSetInfoBlock ADBSInfoPtr æKY ADBOpBlock ADBOpBPtr æFp DeskBus.p æT RECORD æD ADBOpBPtr = ^ADBOpBlock; ADBOpBlock = RECORD dataBuffPtr: Ptr; {address of data buffer} opServiceRtPtr: Ptr; {service routine pointer} opDataAreaPtr: Ptr; {optional data area address} END; æC æKY ADBDataBlock ADBDBlkPtr æFp DeskBus.p æT RECORD æD ADBDBlkPtr = ^ADBDataBlock; ADBDataBlock = PACKED RECORD devType: SignedByte; {device type} origADBAddr: SignedByte; {original ADB Address} dbServiceRtPtr: Ptr; {service routine pointer} dbDataAreaAddr: Ptr; {data area address} END; æC æKY ADBSetInfoBlock ADBSInfoPtr æFp DeskBus.p æT RECORD æD ADBSInfoPtr = ^ADBSetInfoBlock; ADBSetInfoBlock = RECORD siServiceRtPtr: Ptr; {service routine pointer} siDataAreaAddr: Ptr; {data area address} END; æC æKY ADBAddress æFp DeskBus.p æT RECORD æD ADBAddress = SignedByte; æC æKY ADBReInit æFp DeskBus.p æT PROCEDURE æTN A07B æD PROCEDURE ADBReInit; INLINE $A07B; æDT ADBReInit(paramList); æMM æRT 143, 206 æRI V-367, N143 æC Trap macro _ADBReInit ADBReInit reinitializes the entire Apple Desktop Bus. It clears the ADB device table to zeros and places a SendReset command on the bus to reset all devices to their original addresses. ADBReInit has no parameters. Because it does not deallocate ADB resources on the system heap, ADBReInit should not be used for routine bus initialization. Apple strongly recommends against adding devices while the system is running; therefore, you should never call ADBReInit. ADBReInit also calls a routine pointed to by the low memory global JADBProc at the beginning and end of its execution. You can insert your own preprocessing/postprocessing routine by changing the value of JADBProc; ADBReInit conditions it by setting D0 to 0 for preprocessing and to 1 for postprocessing. Your procedure must restore the value of D0 and branch to the original value of JADBProc on exit. JADBProc should be used to de-allocate memory used by the driver (see MacDTS Sample Code “TbltDrvr” for an example), and then it should chain to the procedure originally found in JADBProc. The complete ADBReInit sequence is therefore the following: • JSR to JADBProc with D0 set to 0 • reinitialize the Apple Desktop Bus • clear the ADB device table • JSR to JADBProc with D0 set to 1 æKY ADBOp æFp DeskBus.p æT FUNCTION æD FUNCTION ADBOp(data: Ptr;compRout: ProcPtr;buffer: Ptr;commandNum: INTEGER): OSErr; æDT myVariable := ADBOp(data,compRout,buffer,commandNum); æRT 206 æRI V-368 æC Trap macro _ADBOp On entry: A0: pointer to parameter block D0: commandNum (byte) Parameter block --> 0 buffer pointer --> 4 compRout pointer --> 8 data pointer On exit: D0: result code (byte) The completion routine pointed to by compRout will be passed the following parameters on entry: D0: commandNum (byte) A0: pointer to buffer, data stored as a Pascal string (maximum 8 bytes data preceded by one length byte) A1: pointer to completion routine (compRout) A2: pointer to optional data area (data) ADBOp transmits over the bus the command byte whose value is given by commandNum. The structure of the command byte is given earlier in Figure 1. ADBOp executes only when the ADB is otherwise idle; otherwise it is held in a command queue. It returns an error if the command queue is full. The length of the data buffer pointed to by buffer is contained in its first byte, like a Pascal string. The optional data area pointed to by data is for local storage by the completion routine pointed to by compRout. ADBop should be used sparingly; it is not intended for polling a device. The host automatically polls devices with data to deliver. Result codes noErr No error –1 Unsuccessful completion æKY CountADBs æFp DeskBus.p æT FUNCTION æD FUNCTION CountADBs: INTEGER; æDT myVariable := CountADBs(paramList); æRT 206 æRI V-369 æC Trap macro _CountADBs On exit: D0: number of devices (byte) CountADBs returns a value representing the number of devices connected to the ADB by counting the number of entries in the device table. It has no arguments and returns no error codes. æKY GetIndADB æFp DeskBus.p æT FUNCTION æD FUNCTION GetIndADB(VAR info: ADBDataBlock;devTableIndex: INTEGER): ADBAddress; æDT myVariable := GetIndADB(info,devTableIndex); æRT 206 æRI V-369 æC Trap macro _GetIndADB On entry: A0: pointer to parameter block D0: entry index number; range = 1..CountADBs (byte) Parameter block <-- 0 device type byte (handler ID) <-- 1 original ADB address byte <-- 2 service routine address pointer (compRout) <-- 6 data area address pointer (data) On exit: D0: positive value: current ADB address (byte) negative value: error code (byte) GetIndADB returns information from the ADB device table entry whose index number is given by devTableIndex. ADBDataBlock has this form: TYPE ADBDataBlock = PACKED RECORD devType: SignedByte; {device type (handler ID)} origADBAddr: SignedByte; {original ADB address} dbServiceRtPtr: Ptr; {service routine address (compRout)} dbDataAreaAddr: Ptr {data area address (data)} END; GetIndADB returns the current ADB address of the device. If it is unable to complete execution successfully, GetIndADB returns a negative value. æKY GetADBInfo æFp DeskBus.p æT FUNCTION æD FUNCTION GetADBInfo(VAR info: ADBDataBlock;adbAddr: ADBAddress): OSErr; æDT myVariable := GetADBInfo(info,adbAddr); æRI V-370 æC Trap macro _GetADBInfo On entry: A0: pointer to parameter block D0: ADB address of the device (byte) Parameter block <-- 0 device handler ID byte <-- 1 original ADB address byte <-- 2 service routine address pointer (compRout) <-- 6 data area address pointer (data) On exit: D0: result code (byte) GetADBInfo returns information from the ADB device table entry of the device whose ADB address is given by ABDAddr. The structure of ADBDataBlock is given above under “GetIndADB”. Result codes noErr No error æKY SetADBInfo æFp DeskBus.p æT FUNCTION æD FUNCTION SetADBInfo(VAR info: ADBSetInfoBlock;adbAddr: ADBAddress): OSErr; æDT myVariable := SetADBInfo(info,adbAddr); æRT 206 æRI V-370 æC Trap macro _SetADBInfo On entry: A0: pointer to parameter block D0: ADB address of the device (byte) Parameter block --> 0 service routine address pointer (compRout) --> 4 data area address pointer (data) On exit: D0: result code (byte) SetADBInfo sets the service routine address and the data area address in the ADB device table entry for the device whose ADB address is given by ABDAddr. ADBSetInfoBlock has this form: TYPE ADBSetInfoBlock = RECORD siServiceRtPtr: Ptr; {service routine address (compRout)} siDataAreaAddr: Ptr {data area address (data)} END; Result codes noErr No error Warning: You should send a Flush command to the device after calling it with SetADBInfo, to prevent it sending old data to the new data area address. æKY Devices.p æKL CloseDriver Control GetDCtlEntry KillIO OpenDriver PBControl PBKillIO PBStatus SetChooserAlert Status activDev AuxDCE AuxDCEHandle AuxDCEPtr buttonMsg cdevGenErr cdevMemErr cdevResErr cdevUnset chooserID clearDev closeDev copyDev cursorDev cutDev DCtlEntry DCtlHandle DCtlPtr deactivDev deselectMsg fillListMsg getSelMsg hitDev initDev keyEvtDev macDev newSelMsg nulDev pasteDev selectMsg terminateMsg undoDev updateDev æKY newSelMsg æFp Devices.p æT CONST æD newSelMsg = 12; æC æKY fillListMsg æFp Devices.p æT CONST æD fillListMsg = 13; æC æKY getSelMsg æFp Devices.p æT CONST æD getSelMsg = 14; æC æKY selectMsg æFp Devices.p æT CONST æD selectMsg = 15; æC æKY deselectMsg æFp Devices.p æT CONST æD deselectMsg = 16; æC æKY terminateMsg æFp Devices.p æT CONST æD terminateMsg = 17; æC æKY buttonMsg æFp Devices.p æT CONST æD buttonMsg = 19; æC æKY chooserID æFp Devices.p æT CONST æD chooserID = 1; æC æKY initDev æFp Devices.p æT CONST æD initDev = 0; {Time for cdev to initialize itself} æC »The initDev Message InitDev is an initialization message sent to allow the cdev to allocate its private storage (if any) and do any initial settings to buttons or controls. This message is sent when the user clicks on the cdev’s icon. Note that the dialog, cdev list, and all of the items in the cdev’s 'DITL' except user items will already have been drawn when the initDev message is sent. If your cdev doesn’t need any storage it should return the value that was passed to it in cdevValue. æKY hitDev æFp Devices.p æT CONST æD hitDev = 1; {Hit on one of my items} æC »The hitDev Message A hitDev message is sent when the user has clicked an enabled dialog item that belongs to the cdev. The dialog item number of the item hit is passed in the Item parameter. Remember that the Control Panel’s items precede yours, so you’ll want (Item – numItems) to determine which of your items was hit. If the Control Panel itself has n items, the first of the cdev’s items will be n+1 in the combined dialog item list. A cdev should not depend on any hardcoded value for numItems, since the number of items in Control Panel’s 'DITL' is likely to change in the future. Factoring in numItems need not mean an increase in your code size, or passing and adding numItems everywhere, or foregoing the constants that most developers use to identify specific items. You can do it easily, and neatly, as follows: 1. Subtract numItems from Item right away, and refer to your dialog items with constants as usual throughout the cdev. 2. Write simple envelope routines to enclose Dialog Manager procedures that require item number arguments. Add numItems only locally, within those routines and for the Dialog Manager calls only. This is demonstrated in the sample cdev. æKY closeDev æFp Devices.p æT CONST æD closeDev = 2; {Close yourself} æC »The closeDev Message A closeDev message is sent to the cdev when either the Control Panel is closed or the user selects another cdev. When a cdev receives a closeDev message it should dispose of any storage it has allocated, including the handle stored in cdevValue, if any. æKY nulDev æFp Devices.p æT CONST æD nulDev = 3; {Null event} æC »The nulDev Message A nulDev message is sent to the cdev on every Control Panel run event. This allows the cdev to perform tasks that need to be executed continuously (insertion point blinking, for example). A cdev cannot assume any particular timing of calls from applications. Don’t use nulDev to refresh settings; see activDev, above. æKY updateDev æFp Devices.p æT CONST æD updateDev = 4; {Update event} æC »The updateDev Message An updateDev message is sent to the cdev on every update event. It allows the cdev to perform any updating necessary aside from the standard dialog item updating provided by the Dialog Manager. For example, if the cdev resource contains a picture of the sound control bar, it will probably be a user item, and the picture of the control bar and the volume knob should be redrawn in response to update events. Note that there is no mechanism for determining what to update, as the update region has already been reset. You must redraw all of your user items completely. æKY activDev æFp Devices.p æT CONST æD activDev = 5; {Activate event} æC »The activDev Message An activDev message is sent to the cdev on every activate event. It allows the cdev to reset any items that may have changed while the Control Panel was inactive. It also allows the cdev to send things such as “lists activate” messages. æKY deactivDev æFp Devices.p æT CONST æD deactivDev = 6; {Deactivate event} æC »The deActivDev Message A deActivDev message is sent to the cdev on every deactivate event. It allows the cdev to send deactivate messages to items such as lists. æKY keyEvtDev æFp Devices.p æT CONST æD keyEvtDev = 7; {Key down/auto key} æC »The keyEvtDev Message A keyEvtDev message is sent to the cdev on every keyDown event and autoKey event. It allows the cdev to process key events. On return to the Control Panel, the key event will be processed by a call to dialogSelect in the Dialog Manager. A cdev that does not want the Toolbox Event Manager to do any further processing should change the what field of the EventRecord to nullEvent before returning to the Control Panel. æKY macDev æFp Devices.p æT CONST æD macDev = 8; {Decide whether or not to show up} æC »The macDev Message If the 'mach' resource has a 0 in Softmask and a –1 ($FFFF) in Hardmask, the first message a cdev will get is a macDev message. This is an opportunity for the cdev to determine whether it can run, and whether it should appear in the Control Panel’s cdev list. The cdev can do its own check to see which machine it is being run on, what hardware is connected, and what is in the slots (if it has slots). The cdev must then return a function result of 1 or 0. If a 0 is returned, the Control Panel will not display the cdev in the icon list. (Note that the Control Panel does not interpret this 0 or 1 as an error message as described under “Cdev Error Checking”.) The macDev call happens only once, and only when Softmask and Hardmask are 0 and FFFF. It is always the first call made to the cdev. æKY undoDev æFp Devices.p æT CONST æD undoDev = 9; æC æKY cutDev æFp Devices.p æT CONST æD cutDev = 10; æC æKY copyDev æFp Devices.p æT CONST æD copyDev = 11; æC æKY pasteDev æFp Devices.p æT CONST æD pasteDev = 12; æC æKY clearDev æFp Devices.p æT CONST æD clearDev = 13; æC æKY cursorDev æFp Devices.p æT CONST æD cursorDev = 14; æC æKY cdevGenErr æFp Devices.p æT CONST æD cdevGenErr = -1; {General error; gray cdev w/o alert} æC æKY cdevMemErr æFp Devices.p æT CONST æD cdevMemErr = 0; {Memory shortfall; alert user please} æC æKY cdevResErr æFp Devices.p æT CONST æD cdevResErr = 1; {Couldn't get a needed resource; alert} æC æKY cdevUnset æFp Devices.p æT CONST æD cdevUnset = 3; { cdevValue is initialized to this} æC »CDEV ERROR CHECKING _______________________________________________________________________________ Because a desk accessory may be called into many strange and wonderful situations, careful attention must be paid to error checking. The two most common error conditions are missing resources and lack of memory. Some error reporting and recovery facilities have been provided in the Control Panel to help with errors encountered in a cdev. Because the Control Panel has no direct information about the cdev, the cdev’s code must be able to detect and recover from error conditions on its own. If the recovery cannot be effected the cdev must dispose of any memory it has allocated, and exit back to the Control Panel with an error code. Following a shutdown, the Control Panel can help report the error condition to the user and prevent accidental reentry into the cdev that might result from such things as an update event. A cdev can request three different error reporting mechanisms from the Control Panel: • If a memory error has occured, then, after the cdev has safely shut itself down, it may request the Control Panel to issue an out-of-memory error message and gray out (paint over with the background pattern) the cdev area of the Control Panel window. It will remain grayed until another cdev is selected. The Control Panel window itself is not closed since other cdevs may still be able to function in the environment. • If a resource error is detected, the cdev may request that a can’t-find-needed-resource error message be issued. • The cdev may display its own error message and then call on the Control Panel to gray its area. The Control Panel uses the cdevValue parameter to send status information to the cdev, and a proper cdev uses its function value to send information back to the Control Panel. In the absence of errors, the same value passes back and forth: the Control Panel puts the last function value it received into cdevValue when it calls the cdev; the cdev returns the value it finds there as the function value. The cdev may want to keep a handle to its own storage, in which case passing it as the function value ensures its availability, since the Control Panel will pass it back in cdevValue at the next call. Four constants have been defined for this cdev/Control Panel communication: CONST cdevUnset = 3; {initial value passed in cdevValue} cdevGenErr = -1; {generic cdev error} cdevMemErr = 0; {insufficient memory for cdev execution} cdevResErr = 1; {missing resource needed by cdev} After the macDev call, the Control Panel sends cdevUnset in cdevValue, so that until an error occurs or the cdev uses its function value as a handle, cdevUnset is passed back and forth. If the cdev encounters an error, it should dispose of all handles and pointers it has set up, strip the stack back to the same position as a normal exit, and return one of the three error codes as the function result. The Control Panel will respond as follows: Function Message to Control Panel Action Result Control Panel cdevGenErr The cdev has encountered an Gray out the cdev’s area, error from which it cannot send a 0 in cdevValue in recover, but do not put up succeeding cdev calls an error dialog. cdevMemErr The cdev has determined that Gray out cdev’s area, put there is not enough memory to up error dialog, send a 0 execute; please put up a in cdevValue in succeeding memory error dialog. cdev calls. cdevResErr The cdev can’t find a needed Gray out cdev’s area, put resource; please put up a up error dialog, send a 0 resource error dialog. in cdevValue in succeeding cdev calls. all other values, No error conditions. Send the value back in either handles cdevValue. or cdevUnset The cdev code should check cdevValue at entry. A 0 means that the Control Panel has responded to a cdev error message by shutting down the cdev and displaying an error dialog if one was requested. The cdev should immediately exit. Once the Control Panel has responded to an error message from a cdev it will no longer respond to any return values until another cdev is launched. æKY DCtlEntry DCtlPtr DCtlHandle æFp Devices.p æT RECORD æD DCtlPtr = ^DCtlEntry; DCtlHandle = ^DCtlPtr; DCtlEntry = RECORD dCtlDriver: Ptr; dCtlFlags: INTEGER; dCtlQHdr: QHdr; dCtlPosition: LONGINT; dCtlStorage: Handle; dCtlRefNum: INTEGER; dCtlCurTicks: LONGINT; dCtlWindow: WindowPtr; dCtlDelay: INTEGER; dCtlEMask: INTEGER; dCtlMenu: INTEGER; END; æC »Device Control Entry The first time a driver is opened, information about it is read into a structure in memory called a device control entry. A device control entry contains the header of the driver’s I/O queue, the location of the driver’s routines, and other information. A device control entry is a 40-byte relocatable block located in the system heap. It’s locked while the driver is open, and unlocked while the driver is closed. Most of the data in the device control entry is stored and accessed only by the Device Manager, but in some cases the driver itself must store into it. The structure of a device control entry is shown below; note that the first four words of the driver are copied into the dCtlFlags, dCtlDelay, dCtlEMask, and dCtlMenu fields. TYPE DCtlEntry = RECORD dCtlDriver: Ptr; {pointer to ROM driver or } { handle to RAM driver} dCtlFlags: INTEGER; {flags} dCtlQHdr: QHdr; {driver I/O queue header} dCtlPosition: LONGINT; {byte position used by Read } { and Write calls} dCtlStorage: Handle; {handle to RAM driver's } { private storage} dCtlRefNum: INTEGER; {driver reference number} dCtlCurTicks: LONGINT; {used internally} dCtlWindow: WindowPtr; {pointer to driver's window} dCtlDelay: INTEGER; {number of ticks between } { periodic actions} dCtlEMask: INTEGER; {desk accessory event mask} dCtlMenu: INTEGER {menu ID of menu associated { with driver} END; DCtlPtr = ^DCtlEntry; DCtlHandle = ^DCtlPtr; The low-order byte of the dCtlFlags word contains the following flags: Bit number Meaning 5 Set if driver is open 6 Set if driver is RAM-based 7 Set if driver is currently executing Assembly-language note: These flags can be accessed with the global constants dOpened, dRAMBased, and drvrActive. The high-order byte of the dCtlFlags word contains flags copied from the drvrFlags word of the driver, as described above. DCtlQHdr contains the header of the driver’s I/O queue (described below). DCtlPosition is used only by drivers of block devices, and indicates the current source or destination position of a Read or Write call. The position is given as a number of bytes beyond the physical beginning of the medium used by the device. For example, if one logical block of data has just been read from a 3 1/2-inch disk via the Disk Driver, dCtlPosition will be 512. ROM drivers generally use locations in low memory for their local storage. RAM drivers may reserve memory within their code space, or allocate a relocatable block and keep a handle to it in dCtlStorage (if the block resides in the application heap, its handle will be set to NIL when the heap is reinitialized). You can get a handle to a driver’s device control entry by calling the Device Manager function GetDCtlEntry. æKY AuxDCE AuxDCEPtr AuxDCEHandle æFp Devices.p æT RECORD æD AuxDCEPtr = ^AuxDCE; AuxDCEHandle = ^AuxDCEPtr; AuxDCE = PACKED RECORD dCtlDriver: Ptr; dCtlFlags: INTEGER; dCtlQHdr: QHdr; dCtlPosition: LONGINT; dCtlStorage: Handle; dCtlRefNum: INTEGER; dCtlCurTicks: LONGINT; dCtlWindow: GrafPtr; dCtlDelay: INTEGER; dCtlEMask: INTEGER; dCtlMenu: INTEGER; dCtlSlot: Byte; dCtlSlotId: Byte; dCtlDevBase: LONGINT; dCtlOwner: Ptr; dCtlExtDev: Byte; fillByte: Byte; END; æC æKY GetDCtlEntry æFp Devices.p æT FUNCTION æD FUNCTION GetDCtlEntry(refNum: INTEGER): DCtlHandle; æDT myVariable := GetDCtlEntry(refNum); æMM æRT 71 æRI II-190 æC [Not in ROM] GetDCtlEntry returns a handle to the device control entry of the device driver having the reference number refNum. Assembly-language note: You can get a handle to a driver’s device control entry from the unit table, as described below. æKY SetChooserAlert æFp Devices.p æT FUNCTION æD FUNCTION SetChooserAlert(f: BOOLEAN): BOOLEAN; æDT myVariable := SetChooserAlert(f); æRI V-431 æC f f is true, the Chooser will put up the page setup alert; if f is false it won’t. SetChooserAlert returns the original alert state. The application should restore the original alert state when it exits. _____________________________________________________________________________________ Assembly-language note: If the psAlert bit of the low-memory global HiliteMode is 0 then no page setup alert will be generated. Applications that set or clear this bit must be sure not to affect any other bits in the byte and to restore the bit as they leave. HiliteMode equ $938 psAlert equ 6 bclr #psAlert,HiliteMode bset #psAlert,HiliteMode _____________________________________________________________________________________ æKY OpenDriver æFp Devices.p æT FUNCTION æD FUNCTION OpenDriver(name: Str255;VAR drvrRefNum: INTEGER): OSErr; æDT myVariable := OpenDriver(name,drvrRefNum); æMM æRI II-178, N14-2 æC [Not in ROM] OpenDriver opens the device driver specified by name and returns its reference number in refNum. Result codes noErr No error badUnitErr Bad reference number dInstErr Couldn’t find driver in resource file openErr Driver can’t perform the requested reading or writing unitEmptyErr Bad reference number æKY CloseDriver æFp Devices.p æT FUNCTION æD FUNCTION CloseDriver(refNum: INTEGER): OSErr; æDT myVariable := CloseDriver(refNum); æRI II-178 æC [Not in ROM] CloseDriver closes the device driver having the reference number refNum. Any pending I/O is completed, and the memory used by the driver is released. Warning: Before using this command to close a particular driver, refer to the chapter describing the driver for the consequences of closing it. Result codes noErr No error badUnitErr Bad reference number dRemoveErr Attempt to remove an open driver unitEmptyErr Bad reference number æKY Control æFp Devices.p æT FUNCTION æD FUNCTION Control(refNum: INTEGER;csCode: INTEGER;csParamPtr: Ptr): OSErr; æDT myVariable := Control(refNum,csCode,csParamPtr); æMM æRI II-186 æC [Not in ROM] Control sends control information to the device driver having the reference number refNum. The type of information sent is specified by csCode, and the information itself is pointed to by csParamPtr. The values passed in csCode and pointed to by csParamPtr depend on the driver being called. Result codes noErr No error badUnitErr Bad reference number notOpenErr Driver isn’t open unitEmptyErr Bad reference number controlErr Driver can’t respond to this Control call æKY Status æFp Devices.p æT FUNCTION æD FUNCTION Status(refNum: INTEGER;csCode: INTEGER;csParamPtr: Ptr): OSErr; æDT myVariable := Status(refNum,csCode,csParamPtr); æMM æRI II-186 æC [Not in ROM] Status returns status information about the device driver having the reference number refNum. The type of information returned is specified by csCode, and the information itself is pointed to by csParamPtr. The values passed in csCode and pointed to by csParamPtr depend on the driver being called. Result codes noErr No error badUnitErr Bad reference number notOpenErr Driver isn’t open unitEmptyErr Bad reference number statusErr Driver can’t respond to this Status call æKY KillIO æFp Devices.p æT FUNCTION æD FUNCTION KillIO(refNum: INTEGER): OSErr; æDT myVariable := KillIO(refNum); æRI II-179 æC [Not in ROM] KillIO terminates all current and pending I/O with the device driver having the reference number refNum. Result codes noErr No error badUnitErr Bad reference number unitEmptyErr Bad reference number æKY PBControl æFp Devices.p æT FUNCTION æD FUNCTION PBControl(paramBlock: ParmBlkPtr;aSync: BOOLEAN): OSErr; æDT myVariable := PBControl(paramBlock,aSync); æMM æRI II-186 æC Trap macro _Control Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 22 ioVRefNum word --> 24 ioRefNum word --> 26 csCode word --> 28 csParam record PBControl sends control information to the device driver having the reference number ioRefNum; the drive number, if any, is specified by ioVRefNum. The type of information sent is specified by csCode, and the information itself begins at csParam. The values passed in csCode and csParam depend on the driver being called. Result codes noErr No error badUnitErr Bad reference number notOpenErr Driver isn’t open unitEmptyErr Bad reference number controlErr Driver can’t respond to this Control call æKY PBStatus æFp Devices.p æT FUNCTION æD FUNCTION PBStatus(paramBlock: ParmBlkPtr;aSync: BOOLEAN): OSErr; æDT myVariable := PBStatus(paramBlock,aSync); æMM æRI II-186 æC Trap macro _Status Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 22 ioVRefNum word --> 24 ioRefNum word --> 26 csCode word <-- 28 csParam record PBStatus returns status information about the device driver having the reference number ioRefNum; the drive number, if any, is specified by ioVRefNum. The type of information returned is specified by csCode, and the information itself begins at csParam. The values passed in csCode and csParam depend on the driver being called. Result codes noErr No error badUnitErr Bad reference number notOpenErr Driver isn’t open unitEmptyErr Bad reference number statusErr Driver can’t respond to this Status call æKY PBKillIO æFp Devices.p æT FUNCTION æD FUNCTION PBKillIO(paramBlock: ParmBlkPtr;aSync: BOOLEAN): OSErr; æDT myVariable := PBKillIO(paramBlock,aSync); æRI II-187 æC Trap macro _KillIO Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word PBKillIO stops any current I/O request being processed, and removes all pending I/O requests from the I/O queue of the device driver having the reference number ioRefNum. The completion routine of each pending I/O request is called, with the ioResult field of each request equal to the result code abortErr. Result codes noErr No error badUnitErr Bad reference number unitEmptyErr Bad reference number æKY Dialogs.p æKL Alert CautionAlert CloseDialog CouldAlert CouldDialog DialogSelect DisposDialog DlgCopy DlgCut DlgDelete DlgPaste DrawDialog ErrorSound FindDItem FreeAlert FreeDialog GetAlrtStage GetDItem GetIText GetNewDialog HideDItem InitDialogs IsDialogEvent ModalDialog NewCDialog NewDialog NoteAlert ParamText ResetAlrtStage SelIText SetDAFont SetDItem SetIText ShowDItem StopAlert UpdtDialog AlertTemplate AlertTHndl AlertTPtr btnCtrl cancel cautionIcon chkCtrl ctrlItem DialogPeek DialogPtr DialogRecord DialogTemplate DialogTHndl DialogTPtr editText iconItem itemDisable noteIcon ok picItem radCtrl resCtrl StageList statText stopIcon userItem æKY ctrlItem æFp Dialogs.p æT CONST æD ctrlItem = 4; æC æKY btnCtrl æFp Dialogs.p æT CONST æD btnCtrl = 0; æC æKY chkCtrl æFp Dialogs.p æT CONST æD chkCtrl = 1; æC æKY radCtrl æFp Dialogs.p æT CONST æD radCtrl = 2; æC æKY resCtrl æFp Dialogs.p æT CONST æD resCtrl = 3; æC æKY statText æFp Dialogs.p æT CONST æD statText = 8; æC æKY editText æFp Dialogs.p æT CONST æD editText = 16; æC æKY iconItem æFp Dialogs.p æT CONST æD iconItem = 32; æC æKY picItem æFp Dialogs.p æT CONST æD picItem = 64; æC æKY userItem æFp Dialogs.p æT CONST æD userItem = 0; æC æKY itemDisable æFp Dialogs.p æT CONST æD itemDisable = 128; æC æKY ok æFp Dialogs.p æT CONST æD ok = 1; æC æKY cancel æFp Dialogs.p æT CONST æD cancel = 2; æC æKY stopIcon æFp Dialogs.p æT CONST æD stopIcon = 0; æC æKY noteIcon æFp Dialogs.p æT CONST æD noteIcon = 1; æC æKY cautionIcon æFp Dialogs.p æT CONST æD cautionIcon = 2; æC æKY DialogRecord DialogPeek æFp Dialogs.p æT RECORD æD DialogPeek = ^DialogRecord; DialogRecord = RECORD window: WindowRecord; items: Handle; textH: TEHandle; editField: INTEGER; editOpen: INTEGER; aDefItem: INTEGER; END; æC »The DialogRecord Data Type For those who want to know more about the data structure of a dialog record, the exact structure is given here. TYPE DialogRecord = RECORD window: WindowRecord; {dialog window} items: Handle; {item list} textH: TEHandle; {current editText item} editField: INTEGER; {editText item number minus 1} editOpen: INTEGER; {used internally} aDefItem: INTEGER {default button item number} END; The window field contains the window record for the dialog window. The items field contains a handle to the item list used for the dialog. (Remember that after reading an item list from a resource file, the Dialog Manager makes a copy of it and uses that copy.) Note: To get or change information about an item in a dialog, you pass the dialog pointer and the item number to a Dialog Manager procedure. You’ll never access information directly through the handle to the item list. The Dialog Manager uses the next three fields when there are one or more editText items in the dialog. If there’s more than one such item, these fields apply to the one that currently is selected or displays the insertion point. The textH field contains the handle to the edit record used by TextEdit. EditField is 1 less than the item number of the current editText item, or –1 if there’s no editText item in the dialog. The editOpen field is used internally by the Dialog Manager. Note: Actually, a single edit record is shared by all editText items; any changes you make to it will apply to all such items. See the TextEdit chapter for details about what kinds of changes you can make. The aDefItem field is used for modal dialogs and alerts, which are treated internally as special modal dialogs. It contains the item number of the default button. The default button for a modal dialog is the first item in the item list, so this field contains 1 for modal dialogs. The default button for an alert is specified in the alert template; see the following section for more information. æKY DialogPtr æFp Dialogs.p æT RECORD æD DialogPtr = WindowPtr; æC »Dialog Pointers There are two types of dialog pointer, DialogPtr and DialogPeek, analogous to the window pointer types WindowPtr and WindowPeek. Most programmers will only need to use DialogPtr. The Dialog Manager defines the following type of dialog pointer: TYPE DialogPtr = WindowPtr; It can do this because the first field of a dialog record contains the window record for the dialog window. This type of pointer can be used to access fields of the window record or can be passed to Window Manager routines that expect window pointers as parameters. Since the WindowPtr data type is itself defined as GrafPtr, this type of dialog pointer can also be used to access fields of the dialog window’s grafPort or passed to QuickDraw routines that expect pointers to grafPorts as parameters. For programmers who want to access dialog record fields beyond the window record, the Dialog Manager also defines the following type of dialog pointer: TYPE DialogPeek = ^DialogRecord; Assembly-language note: From assembly language, of course, there’s no type checking on pointers, and the two types of pointer are equal. _______________________________________________________________________________ »The DialogRecord Data Type For those who want to know more about the data structure of a dialog record, the exact structure is given here. TYPE DialogRecord = RECORD window: WindowRecord; {dialog window} items: Handle; {item list} textH: TEHandle; {current editText item} editField: INTEGER; {editText item number minus 1} editOpen: INTEGER; {used internally} aDefItem: INTEGER {default button item number} END; The window field contains the window record for the dialog window. The items field contains a handle to the item list used for the dialog. (Remember that after reading an item list from a resource file, the Dialog Manager makes a copy of it and uses that copy.) Note: To get or change information about an item in a dialog, you pass the dialog pointer and the item number to a Dialog Manager procedure. You’ll never access information directly through the handle to the item list. The Dialog Manager uses the next three fields when there are one or more editText items in the dialog. If there’s more than one such item, these fields apply to the one that currently is selected or displays the insertion point. The textH field contains the handle to the edit record used by TextEdit. EditField is 1 less than the item number of the current editText item, or –1 if there’s no editText item in the dialog. The editOpen field is used internally by the Dialog Manager. Note: Actually, a single edit record is shared by all editText items; any changes you make to it will apply to all such items. See the TextEdit chapter for details about what kinds of changes you can make. The aDefItem field is used for modal dialogs and alerts, which are treated internally as special modal dialogs. It contains the item number of the default button. The default button for a modal dialog is the first item in the item list, so this field contains 1 for modal dialogs. The default button for an alert is specified in the alert template; see the following section for more information. _______________________________________________________________________________ »THE DRAWING ENVIRONMENT: GRAFPORT _______________________________________________________________________________ A grafPort is a complete drawing environment that defines where and how graphic operations will take place. You can have many grafPorts open at once, and each one will have its own coordinate system, drawing pattern, background pattern, pen size and location, character font and style, and bit map in which drawing takes place. You can instantly switch from one port to another. GrafPorts are the structures upon which a program builds windows, which are fundamental to the Macintosh “overlapping windows” user interface. Besides being used for windows on the screen, grafPorts are used for printing and for off-screen drawing. A grafPort is defined as follows: TYPE GrafPtr = ^GrafPort; GrafPort = RECORD device: INTEGER; {device-specific information} portBits: BitMap; {grafPort's bit map} portRect: Rect; {grafPort's rectangle} visRgn: RgnHandle; {visible region} clipRgn: RgnHandle; {clipping region} bkPat: Pattern; {background pattern} fillPat: Pattern; {fill pattern} pnLoc: Point; {pen location} pnSize: Point; {pen size} pnMode: INTEGER; {pen's transfer mode} pnPat: Pattern; {pen pattern} pnVis: INTEGER; {pen visibility} txFont: INTEGER; {font number for text} txFace: Style; {text's character style} txMode: INTEGER; {text's transfer mode} txSize: INTEGER; {font size for text} spExtra: Fixed; {extra space} fgColor: LONGINT; {foreground color} bkColor: LONGINT; {background color} colrBit: INTEGER; {color bit} patStretch: INTEGER; {used internally} picSave: Handle; {picture being saved} rgnSave: Handle; {region being saved} polySave: Handle; {polygon being saved} grafProcs: QDProcsPtr {low-level drawing routines} END; Note that picSave is a Handle used internally by QuickDraw while it is saving a picture, and rgnSave and polySave are used by QuickDraw as flags; they are set to “1” when the corresponding action is taking place. All QuickDraw operations refer to grafPorts via grafPtrs. (For historical reasons, grafPort is one of the few objects in the Macintosh system software that’s referred to by a pointer rather than a handle.) Warning: You can access all fields and subfields of a grafPort normally, but you should not store new values directly into them. QuickDraw has routines for altering all fields of a grafPort, and using these routines ensures that changing a grafPort produces no unusual side effects. The device field of a grafPort contains device-specific information that’s used by the Font Manager to achieve the best possible results when drawing text in the grafPort. There may be physical differences in the same logical font for different output devices, to ensure the highest-quality printing on the device being used. The default value of the device field is 0, for best results on output to the screen. For more information, see the Font Manager chapter. The portBits field is the bit map that points to the bit image to be used by the grafPort. The default bit map uses the entire screen as its bit image. The bit map may be changed to indicate a different structure in memory: All graphics routines work in exactly the same way regardless of whether their effects are visible on the screen. A program can, for example, prepare an image to be printed on a printer without ever displaying the image on the screen, or develop a picture in an off-screen bit map before transferring it to the screen. The portBits.bounds rectangle determines the coordinate system of the grafPort; all other coordinates in the grafPort are expressed in this system. The portRect field is a rectangle that defines a subset of the bit map that will be used for drawing: All drawing done by the application occurs inside the portRect. Its coordinates are in the coordinate system defined by the portBits.bounds rectangle. The portRect usually falls within the portBits.bounds rectangle, but it’s not required to do so. The portRect usually defines the “writable” interior area of a window, document, or other object on the screen. The visRgn field is manipulated by the Window Manager; you will normally never change a grafPort’s visRgn. It indicates the region of the grafPort that’s actually visible on the screen, that is, the part of the window that’s not covered by other windows. For example, if you move one window in front of another, the Window Manager logically removes the area of overlap from the visRgn of the window in back. When you draw into the back window, whatever’s being drawn is clipped to the visRgn so that it doesn’t run over onto the front window. The default visRgn is set to the portRect. The clipRgn is the grafPort’s clipping region, an arbitrary region that you can use to limit drawing to any region within the portRect. If, for example, you want to draw a half circle on the screen, you can set the clipRgn to half the square that would enclose the whole circle, and then draw the whole circle. Only the half within the clipRgn will actually be drawn in the grafPort. The default clipRgn is set arbitrarily large, you have full control over its setting; as a matter of recommended programming practice, it is advisable to make the default clipRgn rectangle smaller. Figure 10 illustrates a typical bit map (as defined by portBits), portRect, visRgn, and clipRgn. •••Refer to Figure 10.••• Figure 10–GrafPort Regions The bkPat and fillPat fields of a grafPort contain patterns used by certain QuickDraw routines. BkPat is the “background” pattern that’s used when an area is erased or when bits are scrolled out of it. When asked to fill an area with a specified pattern, QuickDraw stores the given pattern in the fillPat field and then calls a low-level drawing routine that gets the pattern from that field. The various graphic operations are discussed in detail later in the descriptions of individual QuickDraw routines. Of the next ten fields, the first five determine characteristics of the graphics pen and the last five determine characteristics of any text that may be drawn; these are described in separate sections below. The fgColor, bkColor, and colrBit fields contain values related to drawing in color. FgColor is the grafPort’s foreground color and bkColor is its background color. ColrBit tells the color imaging software which plane of the color picture to draw into. For more information, see “Drawing in Color” in the section “General Discussion of Drawing”. The patStretch field is used during output to a printer to expand patterns if necessary. The application should not change its value. The picSave, rgnSave, and polySave fields reflect the state of picture, region, and polygon definition, respectively. The application shouldn’t be concerned about exactly what information the handle, if any, leads to; you may, however, save the current value of rgnSave, set the field to NIL to disable the region definition, and later restore it to the saved value to resume the region definition. The picSave and polySave fields work similarly for pictures and polygons. Finally, the grafProcs field may point to a special data structure that the application stores into if it wants to customize QuickDraw drawing routines or use QuickDraw in other advanced, highly specialized ways (see “Customizing QuickDraw Operations”). If grafProcs is NIL, QuickDraw responds in the standard ways described in this chapter. _______________________________________________________________________________ »Pen Characteristics The pnLoc, pnSize, pnMode, pnPat, and pnVis fields of a grafPort deal with the graphics “pen”. Each grafPort has one and only one such pen, which is used for drawing lines, shapes, and text. The pen has four characteristics: a location, a size (height and width), a drawing mode, and a drawing pattern (see Figure 11). •••Refer to Figure 11.••• Figure 11–A Graphics Pen The pnLoc field specifies the point where QuickDraw will begin drawing the next line, shape, or character. It can be anywhere on the coordinate plane: There are no restrictions on the movement or placement of the pen. Remember that the pen location is a point in the grafPort’s coordinate system, not a pixel in a bit image. The top left corner of the pen is at the pen location; the pen hangs below and to the right of this point. The pen is rectangular in shape, and its width and height are specified by pnSize. The default size is a 1-by-1-bit square; the width and height can range from (0,0) to (30000,30000). If either the pen width or the pen height is less than 1, the pen will not draw. The pnMode and pnPat fields of a grafPort determine how the bits under the pen are affected when lines or shapes are drawn. The pnPat is a pattern that’s used like the “ink” in the pen. This pattern, like all other patterns drawn in the grafPort, is always aligned with the port’s coordinate system: The top left corner of the pattern is aligned with the top left corner of the portRect, so that adjacent areas of the same pattern will blend into a continuous, coordinated pattern. The pnMode field determines how the pen pattern is to affect what’s already in the bit image when lines or shapes are drawn. When the pen draws, QuickDraw first determines what bits in the bit image will be affected and finds their corresponding bits in the pattern. It then does a bit-by-bit comparison based on the pen mode, which specifies one of eight Boolean operations to perform. The resulting bit is stored into its proper place in the bit image. The pen modes are described under “Transfer Modes” in the section “General Discussion of Drawing”. The pnVis field determines the pen’s visibility, that is, whether it draws on the screen. For more information, see the descriptions of HidePen and ShowPen under “Pen and Line-Drawing Routines” in the “QuickDraw Routines” section. _______________________________________________________________________________ »Text Characteristics The txFont, txFace, txMode, txSize, and spExtra fields of a grafPort determine how text will be drawn—the font, style, and size of characters and how they will be placed in the bit image. QuickDraw can draw characters as quickly and easily as it draws lines and shapes, and in many prepared fonts. Font means the complete set of characters of one typeface. The characters may be drawn in any size and character style (that is, with stylistic variations such as bold, italic, and underline). Figure 12 shows two characters drawn by QuickDraw and some terms associated with drawing text. •••Refer to Figure 12.••• Figure 12–QuickDraw Characters Text is drawn with the base line positioned at the pen location. The txFont field is a font number that identifies the character font to be used in the grafPort. The font number 0 represents the system font. For more information about the system font, the other font numbers recognized by the Font Manager, and the construction, layout, and loading of fonts, see the Font Manager chapter. A character font is defined as a collection of images that make up the individual characters of the font. The characters can be of unequal widths, and they’re not restricted to their “cells”: The lower curl of a lowercase j, for example, can stretch back under the previous character (typographers call this kerning). A font can consist of up to 255 distinct characters, yet not all characters need to be defined in a single font. In addition, each font contains a missing symbol to be drawn in case of a request to draw a character that’s missing from the font. The txFace field controls the character style of the text with values from the set defined by the Style data type: TYPE StyleItem = (bold,italic,underline,outline,shadow,condense,extend); Style = SET OF StyleItem; Assembly-language note: In assembly language, this set is stored as a word whose low-order byte contains bits representing the style. The bit numbers are specified by the following global constants: boldBit .EQU 0 italicBit .EQU 1 ulineBit .EQU 2 outlineBit .EQU 3 shadowBit .EQU 5 extendBit .EQU 6 If all bits are 0, it represents the plain character style. You can apply stylistic variations either alone or in combination; Figure 13 illustrates some as applied to the Geneva font. Most combinations usually look good only for large font sizes. •••Refer to Figure 13.••• Figure 13–Stylistic Variations If you specify bold, each character is repeatedly drawn one bit to the right an appropriate number of times for extra thickness. Italic adds an italic slant to the characters. Character bits above the base line are skewed right; bits below the base line are skewed left. Underline draws a line below the base line of the characters. If part of a character descends below the base line (as “y” in Figure 13), the underline isn’t drawn through the pixel on either side of the descending part. Outline makes a hollow, outlined character rather than a solid one. Shadow also makes an outlined character, but the outline is thickened below and to the right of the character to achieve the effect of a shadow. If you specify bold along with outline or shadow, the hollow part of the character is widened. Condense and extend affect the horizontal distance between all characters, including spaces. Condense decreases the distance between characters and extend increases it, by an amount that the Font Manager determines is appropriate. The txMode field controls the way characters are placed in the bit image. It functions much like a pnMode: When a character is drawn, QuickDraw determines which bits in the bit image will be affected, does a bit-by-bit comparison based on the mode, and stores the resulting bits into the bit image. These modes are described under “Transfer Modes” in the section “General Discussion of Drawing”. Only three of them—srcOr, srcXor, and srcBic—should be used for drawing text. Note: If you use scrCopy, some extra blank space will be appended at the end of the text. The txSize field specifies the font size in points (where “point” is a typographical term meaning approximately 1/72 inch). Any size from 1 to 127 points may be specified. If the Font Manager doesn’t have the font in a specified size, it will scale a size it does have as necessary to produce the size desired. A value of 0 in this field represents the system font size (12 points). Finally, the spExtra field is useful when a line of characters is to be drawn justified such that it’s aligned with both a left and a right margin (sometimes called “full justification”). SpExtra contains a fixed-point number equal to the average number of pixels by which each space character should be widened to fill out the line. The Fixed data type is described in the Macintosh Memory Management: An Introduction chapter. _______________________________________________________________________________ »COORDINATES IN GRAFPORTS _______________________________________________________________________________ Each grafPort has its own local coordinate system. All fields in the grafPort are expressed in these coordinates, and all calculations and actions performed in QuickDraw use the local coordinate system of the currently selected port. Two things are important to remember: • Each grafPort maps a portion of the coordinate plane into a similarly- sized portion of a bit image. • The portBits.bounds rectangle defines the local coordinates for a grafPort. The top left corner of portBits.bounds is always aligned around the first bit in the bit image; the coordinates of that corner “anchor” a point on the grid to that bit in the bit image. This forms a common reference point for multiple grafPorts that use the same bit image (such as the screen); given a portBits.bounds rectangle for each port, you know that their top left corners coincide. The relationship between the portBits.bounds and portRect rectangles is very important: The portBits.bounds rectangle establishes a coordinate system for the port, and the portRect rectangle indicates the section of the coordinate plane (and thus the bit image) that will be used for drawing. The portRect usually falls inside the portBits.bounds rectangle, but it’s not required to do so. When a new grafPort is created, its bit map is set to point to the entire screen, and both the portBits.bounds and the portRect are set to rectangles enclosing the screen. The point (0,0) corresponds to the screen’s top left corner. You can redefine the local coordinates of the top left corner of the grafPort’s portRect, using the SetOrigin procedure. This offsets the coordinates of the grafPort’s portBits.bounds rectangle, recalculating the coordinates of all points in the grafPort to be relative to the new corner coordinates. For example, consider these procedure calls: SetPort(gamePort); SetOrigin(90,80) The call to SetPort sets the current grafPort to gamePort; the call to SetOrigin changes the local coordinates of the top left corner of that port’s portRect to (90,80) (see Figure 14). •••Refer to Figure 14.••• Figure 14–Changing Local Coordinates This offsets the coordinates of the following elements: gamePort^.portBits.bounds gamePort^.portRect gamePort^.visRgn These three elements are always kept “in sync”. Notice that when the local coordinates of a grafPort are offset, the grafPort’s clipRgn and pen location are not offset. A good way to think of it is that the port’s structure “sticks” to the screen, while the document in the grafPort (along with the pen and clipRgn) “sticks” to the coordinate system. For example, in Figure 14, before SetOrigin, the visRgn and clipRgn are the same as the portRect. After the SetOrigin call, the locations of portBits.bounds, portRect, and visRgn do not change on the screen; their coordinates are simply offset. As always, the top left corner of portBits.bounds remains “anchored” around the first bit in the bit image (the first pixel on the screen); the image on the screen doesn’t move as a result of SetOrigin. However, the pen location and clipRgn do move on the screen; the top left corner of the clipRgn is still (100,100), but this location has moved down and to the right, and the pen has similarly moved. If you’re moving, comparing, or otherwise dealing with mathematical items in different grafPorts (for example, finding the intersection of two regions in two different grafPorts), you must adjust to a common coordinate system before you perform the operation. A QuickDraw procedure, LocalToGlobal, lets you convert a point’s local coordinates to a global coordinate system where the top left corner of the bit image is (0,0); by converting the various local coordinates to global coordinates, you can compare and mix them with confidence. For more information, see the description of LocaltoGlobal under “Calculations with Points” in the “QuickDraw Routines” section. æKY DialogTemplate DialogTPtr DialogTHndl æFp Dialogs.p æT RECORD æD DialogTPtr = ^DialogTemplate; DialogTHndl = ^DialogTPtr; DialogTemplate = RECORD boundsRect: Rect; procID: INTEGER; visible: BOOLEAN; filler1: BOOLEAN; goAwayFlag: BOOLEAN; filler2: BOOLEAN; refCon: LONGINT; itemsID: INTEGER; title: Str255; END; æC »Dialog Templates in Memory The data structure of a dialog template is as follows: TYPE DialogTemplate = RECORD boundsRect: Rect; {becomes window's portRect} procID: INTEGER; {window definiton ID} visible: BOOLEAN; {TRUE if visible} filler1: BOOLEAN; {not used} goAwayFlag: BOOLEAN; {TRUE if has go-away region} filler2: BOOLEAN; {not used} refCon: LONGINT; {window's reference value} itemsID: INTEGER; {resource ID of item list} title: Str255 {window's title} END; The filler1 and filler2 fields are there because for historical reasons the goAwayFlag and refCon fields have to begin on a word boundary. The itemsID field contains the resource ID of the dialog’s item list. The other fields are the same as the parameters of the same name in the NewDialog function; they provide information about the dialog window. You access the dialog template by converting the handle returned by the Resource Manager to a template handle: TYPE DialogTHndl = ^DialogTPtr; DialogTPtr = ^DialogTemplate; æKY StageList æFp Dialogs.p æT RECORD æD StageList = PACKED RECORD boldItm4: 0..1; {default button item number - 1} boxDrwn4: BOOLEAN; {true if alert box to be drawn} sound4: 0..3; {sound number} boldItm3: 0..1; boxDrwn3: BOOLEAN; sound3: 0..3; boldItm2: 0..1; boxDrwn2: BOOLEAN; sound2: 0..3; boldItm1: 0..1; boxDrwn1: BOOLEAN; sound1: 0..3; END; æC »Alert Templates in Memory The data structure of an alert template is as follows: TYPE AlertTemplate = RECORD boundsRect: Rect; {becomes window's portRect} itemsID: INTEGER; {resource ID of item list} stages: StageList {alert stage information} END; BoundsRect is the rectangle that becomes the portRect of the window's grafPort. The itemsID field contains the resource ID of the item list for the alert. The information in the stages field determines exactly what should happen at each stage of the alert. It's packed into a word that has the following structure: TYPE StageList = PACKED RECORD boldItm4: 0..1; {default button item number minus 1} boxDrwn4: BOOLEAN; {TRUE if alert box to be drawn} sound4: 0..3 {sound number} boldItm3: 0..1; boxDrwn3: BOOLEAN; sound3: 0..3 boldItm2: 0..1; boxDrwn2: BOOLEAN; sound2: 0..3 boldItm1: 0..1; boxDrwn1: BOOLEAN; sound1: 0..3 END; Notice that the information is stored in reverse order—for the fourth stage first, and for the first stage last. The boldItm field indicates which button should be the default button (and therefore boldly outlined in the alert box). If the first two items in the alert’s item list are the OK button and the Cancel button, respectively, 0 will refer to the OK button and 1 to the Cancel button. The reason for this is that the value of boldItm plus 1 is interpreted as an item number, and normally items 1 and 2 are the OK and Cancel buttons, respectively. Whatever the item having the corresponding item number happens to be, a bold rounded-corner rectangle will be drawn outside its display rectangle. Note: When deciding where to place items in an alert box, be sure to allow room for any bold outlines that may be drawn. The boxDrwn field is TRUE if the alert box is to be drawn. The sound field specifies which sound should be emitted at this stage of the alert, with a number from 0 to 3 that’s passed to the current sound procedure. You can call ErrorSound to specify your own sound procedure; if you don’t, the standard sound procedure will be used (as described earlier in the “Alerts” section). You access the alert template by converting the handle returned by the Resource Manager to a template handle: TYPE AlertTHndl = ^AlertTPtr; AlertTPtr = ^AlertTemplate; Assembly-language note: Rather than offsets into the fields of the StageList data structure, there are masks for accessing the information stored for an alert stage in a stages word; they’re listed in the summary at the end of this chapter. æKY AlertTemplate AlertTPtr AlertTHndl æFp Dialogs.p æT RECORD æD AlertTPtr = ^AlertTemplate; AlertTHndl = ^AlertTPtr; AlertTemplate = RECORD boundsRect: Rect; itemsID: INTEGER; stages: StageList; END; æC »Alert Templates in Memory The data structure of an alert template is as follows: TYPE AlertTemplate = RECORD boundsRect: Rect; {becomes window's portRect} itemsID: INTEGER; {resource ID of item list} stages: StageList {alert stage information} END; BoundsRect is the rectangle that becomes the portRect of the window's grafPort. The itemsID field contains the resource ID of the item list for the alert. The information in the stages field determines exactly what should happen at each stage of the alert. It's packed into a word that has the following structure: TYPE StageList = PACKED RECORD boldItm4: 0..1; {default button item number minus 1} boxDrwn4: BOOLEAN; {TRUE if alert box to be drawn} sound4: 0..3 {sound number} boldItm3: 0..1; boxDrwn3: BOOLEAN; sound3: 0..3 boldItm2: 0..1; boxDrwn2: BOOLEAN; sound2: 0..3 boldItm1: 0..1; boxDrwn1: BOOLEAN; sound1: 0..3 END; Notice that the information is stored in reverse order—for the fourth stage first, and for the first stage last. The boldItm field indicates which button should be the default button (and therefore boldly outlined in the alert box). If the first two items in the alert’s item list are the OK button and the Cancel button, respectively, 0 will refer to the OK button and 1 to the Cancel button. The reason for this is that the value of boldItm plus 1 is interpreted as an item number, and normally items 1 and 2 are the OK and Cancel buttons, respectively. Whatever the item having the corresponding item number happens to be, a bold rounded-corner rectangle will be drawn outside its display rectangle. Note: When deciding where to place items in an alert box, be sure to allow room for any bold outlines that may be drawn. The boxDrwn field is TRUE if the alert box is to be drawn. The sound field specifies which sound should be emitted at this stage of the alert, with a number from 0 to 3 that’s passed to the current sound procedure. You can call ErrorSound to specify your own sound procedure; if you don’t, the standard sound procedure will be used (as described earlier in the “Alerts” section). You access the alert template by converting the handle returned by the Resource Manager to a template handle: TYPE AlertTHndl = ^AlertTPtr; AlertTPtr = ^AlertTemplate; Assembly-language note: Rather than offsets into the fields of the StageList data structure, there are masks for accessing the information stored for an alert stage in a stages word; they’re listed in the summary at the end of this chapter. æKY InitDialogs æFp Dialogs.p æT PROCEDURE æTN A97B æD PROCEDURE InitDialogs(resumeProc: ProcPtr); INLINE $A97B; æDT InitDialogs(resumeProc); æRI I-411, P-107, 112, 174 æC Call InitDialogs once before all other Dialog Manager routines, to initialize the Dialog Manager. InitDialogs does the following initialization: • It saves the pointer passed in resumeProc, if any, for access by the System Error Handler in case a fatal system error occurs. ResumeProc can be a pointer to a resume procedure, as described in the System Error Handler chapter, or NIL if no such procedure is desired. Assembly-language note: InitDialogs stores the address of the resume procedure in a global variable named ResumeProc. • It installs the standard sound procedure. • It passes empty strings to ParamText. æKY ErrorSound æFp Dialogs.p æT PROCEDURE æTN A98C æD PROCEDURE ErrorSound(soundProc: ProcPtr); INLINE $A98C; æDT ErrorSound(soundProc); æRI I-411 æC ErrorSound sets the sound procedure for alerts to the procedure pointed to by soundProc; if you don’t call ErrorSound, the Dialog Manager uses the standard sound procedure. (For details, see the “Alerts” section.) If you pass NIL for soundProc, there will be no sound (or menu bar blinking) at all. Assembly-language note: The address of the sound procedure being used is stored in the global variable DABeeper. æKY NewDialog æFp Dialogs.p æT FUNCTION æTN A97D æD FUNCTION NewDialog(wStorage: Ptr;boundsRect: Rect;title: Str255;visible: BOOLEAN; procID: INTEGER;behind: WindowPtr;goAwayFlag: BOOLEAN;refCon: LONGINT; itmLstHndl: Handle): DialogPtr; INLINE $A97D; æDT myVariable := NewDialog(wStorage,boundsRect,title,visible,procID,behind,goAwayFlag,refCon,itmLstHndl); æMM æRI I-412, P-107, 177 æC NewDialog creates a dialog as specified by its parameters and returns a pointer to the new dialog. The first eight parameters (dStorage through refCon) are passed to the Window Manager function NewWindow, which creates the dialog window; the meanings of these parameters are summarized below. The items parameter is a handle to the dialog’s item list. You can get the items handle by calling the Resource Manager to read the item list from the resource file into memory. Note: Advanced programmers can create their own item lists in memory rather than have them read from a resource file. The exact format is given later under “Formats of Resources for Dialogs and Alerts”. DStorage is analogous to the wStorage parameter of NewWindow; it’s a pointer to the storage to use for the dialog record. If you pass NIL for dStorage, the dialog record will be allocated in the heap (which, in the case of modeless dialogs, may cause the heap to become fragmented). BoundsRect, a rectangle given in global coordinates, determines the dialog window’s size and location. It becomes the portRect of the window’s grafPort. Remember that the top coordinate of this rectangle should be at least 25 points below the top of the screen for a modal dialog, to allow for the menu bar and the border around the portRect, and at least 40 points below the top of the screen for a modeless dialog, to allow for the menu bar and the window’s title bar. Title is the title of a modeless dialog box; pass the empty string for modal dialogs. If the visible parameter is TRUE, the dialog window is drawn on the screen. If it’s FALSE, the window is initially invisible and may later be shown with a call to the Window Manager procedure ShowWindow. Note: NewDialog generates an update event for the entire window contents, so the items aren’t drawn immediately, with the exception of controls. The Dialog Manager calls the Control Manager to draw controls, and the Control Manager draws them immediately rather than via the standard update mechanism. Because of this, the Dialog Manager calls the Window Manager procedure ValidRect for the enclosing rectangle of each control, so the controls won’t be drawn twice. If you find that the other items aren’t being drawn soon enough after the controls, try making the window invisible initially and then calling ShowWindow to show it. ProcID is the window definition ID, which leads to the window definition function for this type of window. The window definition IDs for the standard types of dialog window are dBoxProc for the modal type and documentProc for the modeless type. The behind parameter specifies the window behind which the dialog window is to be placed on the desktop. Pass POINTER(–1) to bring up the dialog window in front of all other windows. GoAwayFlag applies to modeless dialog boxes; if it’s TRUE, the dialog window has a close box in its title bar when the window is active. RefCon is the dialog window’s reference value, which the application may store into and access for any purpose. NewDialog sets the font of the dialog window’s grafPort to the system font or, if you previously called SetDAFont, to the specified font. It also sets the window class in the window record to dialogKind. æKY GetNewDialog æFp Dialogs.p æT FUNCTION æTN A97C æD FUNCTION GetNewDialog(dialogID: INTEGER;dStorage: Ptr;behind: WindowPtr): DialogPtr; INLINE $A97C; æDT myVariable := GetNewDialog(dialogID,dStorage,behind); æMM æRT 4,34 æRI I-413, V-284, N4-1, P-107, 172 æC Like NewDialog (above), GetNewDialog creates a dialog as specified by its parameters and returns a pointer to the new dialog. Instead of having the parameters boundsRect, title, visible, procID, goAwayFlag, and refCon, GetNewDialog has a single dialogID parameter, where dialogID is the resource ID of a dialog template that supplies the same information as those parameters. The dialog template also contains the resource ID of the dialog’s item list. After calling the Resource Manager to read the item list into memory (if it’s not already in memory), GetNewDialog makes a copy of the item list and uses that copy; thus you may have multiple independent dialogs whose items have the same types, locations, and initial contents. The dStorage and behind parameters of GetNewDialog have the same meaning as in NewDialog. Warning: If either the dialog template resource or the item list resource can’t be read, the function result is undefined. Note: GetNewDialog doesn’t release the memory occupied by the resources. The GetNewDialog routine will attempt to load a 'dctb' resource and returns a pointer to a color grafPort if the resource exists. If no 'dctb' resource is present, GetNewDialog returns a pointer to an old grafPort. The dialog color table is copied before it is passed to SetWinSize unless its ctSize field is equal to –1, indicating that the default window colors are to be used instead. The copy is made so that the color table resource can be purged without affecting the dialog. The color dialog item list resource is duplicated as well, so it can be purgeable. æKY CloseDialog æFp Dialogs.p æT PROCEDURE æTN A982 æD PROCEDURE CloseDialog(theDialog: DialogPtr); INLINE $A982; æDT CloseDialog(theDialog); æMM æRI I-413, P-107, 167 æC CloseDialog removes theDialog’s window from the screen and deletes it from the window list, just as when the Window Manager procedure CloseWindow is called. It releases the memory occupied by the following: • The data structures associated with the dialog window (such as the window’s structure, content, and update regions). • All the items in the dialog (except for pictures and icons, which might be shared resources), and any data structures associated with them. For example, it would dispose of the region occupied by the thumb of a scroll bar, or a similar region for some other control in the dialog. CloseDialog does not dispose of the dialog record or the item list. Figure 10 illustrates the effect of CloseDialog (and DisposDialog, described below). •••Refer to Figure 10.••• Figure 10–CloseDialog and DisposDialog Call CloseDialog when you’re done with a dialog if you supplied NewDialog or GetNewDialog with a pointer to the dialog storage (in the dStorage parameter) when you created the dialog. Note: Even if you didn’t supply a pointer to the dialog storage, you may want to call CloseDialog if you created the dialog with NewDialog. You would call CloseDialog if you wanted to keep the item list around (since, unlike GetNewDialog, NewDialog does not use a copy of the item list). æKY DisposDialog æFp Dialogs.p æT PROCEDURE æTN A983 æD PROCEDURE DisposDialog(theDialog: DialogPtr); INLINE $A983; æDT DisposDialog(theDialog); æRI I-415 æC DisposDialog calls CloseDialog (above) and then releases the memory occupied by the dialog’s item list and dialog record. Call DisposDialog when you’re done with a dialog if you let the dialog record be allocated in the heap when you created the dialog (by passing NIL as the dStorage parameter to NewDialog or GetNewDialog). æKY CouldDialog æFp Dialogs.p æT PROCEDURE æTN A979 æD PROCEDURE CouldDialog(dialogID: INTEGER); INLINE $A979; æDT CouldDialog(dialogID); æMM æRI I-415, V-284 æC CouldDialog makes the dialog template having the given resource ID unpurgeable (reading it into memory if it’s not already there). It does the same for the dialog window’s definition function, the dialog’s item list resource, and any items defined as resources. This is useful if the dialog box may come up when the resource file isn’t accessible, such as during a disk copy. Warning: CouldDialog assumes your dialogs use the system font; if you’ve changed the font with SetDAFont, calling CouldDialog doesn’t make the font unpurgeable. The CouldDialog procedure makes the dialog color table template unpurgeable (reading it into memory if it isn’t already there), if it exists. It does the same for the dialog’s color item list, if it has one. Warning: CouldDialog doesn’t load or make 'FONT' or 'FOND' resources indicated in the color item list unpurgeable. æKY FreeDialog æFp Dialogs.p æT PROCEDURE æTN A97A æD PROCEDURE FreeDialog(dialogID: INTEGER); INLINE $A97A; æDT FreeDialog(dialogID); æMM æRI I-415, V-284 æC Given the resource ID of a dialog template previously specified in a call to CouldDialog, FreeDialog undoes the effect of CouldDialog (by making the resources purgeable). It should be called when there’s no longer a need to keep the resources in memory. Given the resource ID of a dialog template previously specified in a call to CouldDialog, the FreeDialog routine undoes the effect of CouldDialog, by restoring the original purge state of the color table and color item list resources. æKY ParamText æFp Dialogs.p æT PROCEDURE æTN A98B æD PROCEDURE ParamText(param0: Str255;param1: Str255;param2: Str255;param3: Str255); INLINE $A98B; æDT ParamText(param0,param1,param2,param3); æMM æRI I-421 æC ParamText provides a means of substituting text in statText items: param0 through param3 will replace the special strings '^0' through '^3' in all statText items in all subsequent dialog or alert boxes. Pass empty strings for parameters not used. Assembly-language note: Assembly-language programmers may pass NIL for parameters not used or for strings that are not to be changed. For example, if the text is defined as 'Cannot open document ^0' and docName is a string variable containing a document name that the user typed, you can call ParamText(docName,' ',' ',' ') Note: All strings that may need to be translated to other languages should be stored in resource files. Assembly-language note: The Dialog Manager stores handles to the four ParamText parameters in a global array named DAStrings. æKY ModalDialog æFp Dialogs.p æT PROCEDURE æTN A991 æD PROCEDURE ModalDialog(filterProc: ProcPtr;VAR itemHit: INTEGER); INLINE $A991; æDT ModalDialog(filterProc,itemHit); æMM æRT 34, 203 æRI I-415, N34-2, 3, P-108, 176 æC Call ModalDialog after creating a modal dialog and bringing up its window in the frontmost plane. ModalDialog repeatedly gets and handles events in the dialog’s window; after handling an event involving an enabled dialog item, it returns with the item number in itemHit. Normally you’ll then do whatever is appropriate as a response to an event in that item. ModalDialog gets each event by calling the Toolbox Event Manager function GetNextEvent. If the event is a mouse-down event outside the content region of the dialog window, ModalDialog emits sound number 1 (which should be a single beep) and gets the next event; otherwise, it filters and handles the event as described below. Note: Once before getting each event, ModalDialog calls SystemTask, a Desk Manager procedure that must be called regularly so that desk accessories will work properly. The filterProc parameter determines how events are filtered. If it’s NIL, the standard filterProc function is executed; this causes ModalDialog to return 1 in itemHit if the Return key or Enter key is pressed. If filterProc isn’t NIL, ModalDialog filters events by executing the function it points to. Your filterProc function should have three parameters and return a Boolean value. For example, this is how it would be declared if it were named MyFilter: FUNCTION MyFilter (theDialog: DialogPtr; VAR theEvent: EventRecord; VAR itemHit: INTEGER) : BOOLEAN; A function result of FALSE tells ModalDialog to go ahead and handle the event, which either can be sent through unchanged or can be changed to simulate a different event. A function result of TRUE tells ModalDialog to return immediately rather than handle the event; in this case, the filterProc function sets itemHit to the item number that ModalDialog should return. Note: If you want it to be consistent with the standard filterProc function, your function should at least check whether the Return key or Enter key was pressed and, if so, return 1 in itemHit and a function result of TRUE. You can use the filterProc function, for example, to treat a typed character in a special way (such as ignore it, or make it have the same effect as another character or as clicking a button); in this case, the function would test for a key-down event with that character. As another example, suppose the dialog box contains a userItem whose procedure draws a clock with the current time displayed. The filterProc function can call that procedure and return FALSE without altering the current event. Note: ModalDialog calls GetNextEvent with a mask that excludes disk-inserted events. To receive disk-inserted events, your filterProc function can call GetNextEvent (or EventAvail) with a mask that accepts only that type of event. ModalDialog handles the events for which the filterProc function returns FALSE as follows: • In response to an activate or update event for the dialog window, ModalDialog activates or updates the window. • If the mouse button is pressed in an editText item, ModalDialog responds to the mouse activity as appropriate (displaying an insertion point or selecting text). If a key-down event occurs and there’s an editText item, text entry and editing are handled in the standard way for such items (except that if the Command key is down, ModalDialog responds as though it’s not). In either case, ModalDialog returns if the editText item is enabled or does nothing if it’s disabled. If a key-down event occurs when there’s no editText item, ModalDialog does nothing. • If the mouse button is pressed in a control, ModalDialog calls the Control Manager function TrackControl. If the mouse button is released inside the control and the control is enabled, ModalDialog returns; otherwise, it does nothing. • If the mouse button is pressed in any other enabled item in the dialog box, ModalDialog returns. If the mouse button is pressed in any other disabled item or in no item, or if any other event occurs, ModalDialog does nothing. æKY IsDialogEvent æFp Dialogs.p æT FUNCTION æTN A97F æD FUNCTION IsDialogEvent(theEvent: EventRecord): BOOLEAN; INLINE $A97F; æDT myVariable := IsDialogEvent(theEvent); æRI I-416, N5-1, P-108, 175 æC If your application includes any modeless dialogs, call IsDialogEvent after calling the Toolbox Event Manager function GetNextEvent. Warning: If your modeless dialog contains any editText items, you must call IsDialogEvent (and then DialogSelect) even if GetNextEvent returns FALSE; otherwise your dialog won’t receive null events and the caret won’t blink. Pass the current event in theEvent. IsDialogEvent determines whether theEvent needs to be handled as part of a dialog. If theEvent is an activate or update event for a dialog window, a mouse-down event in the content region of an active dialog window, or any other type of event when a dialog window is active, IsDialogEvent returns TRUE; otherwise, it returns FALSE. When FALSE is returned, just handle the event yourself like any other event that’s not dialog-related. When TRUE is returned, you’ll generally end up passing the event to DialogSelect for it to handle (as described below), but first you should do some additional checking: • DialogSelect doesn’t handle keyboard equivalents of commands. Check whether the event is a key-down event with the Command key held down and, if so, carry out the command if it’s one that applies when a dialog window is active. (If the command doesn’t so apply, do nothing.) • In special cases, you may want to bypass DialogSelect or do some preprocessing before calling it. If so, check for those events and respond accordingly. You would need to do this, for example, if the dialog is to respond to disk-inserted events. For cases other than these, pass the event to DialogSelect for it to handle. æKY DialogSelect æFp Dialogs.p æT FUNCTION æTN A980 æD FUNCTION DialogSelect(theEvent: EventRecord;VAR theDialog: DialogPtr;VAR itemHit: INTEGER): BOOLEAN; INLINE $A980; æDT myVariable := DialogSelect(theEvent,theDialog,itemHit); æMM æRT 34 æRI I-417, N34-3, P-108, 168 æC You’ll normally call DialogSelect when IsDialogEvent returns TRUE, passing in theEvent an event that needs to be handled as part of a modeless dialog. DialogSelect handles the event as described below. If the event involves an enabled dialog item, DialogSelect returns a function result of TRUE with the dialog pointer in theDialog and the item number in itemHit; otherwise, it returns FALSE with theDialog and itemHit undefined. Normally when DialogSelect returns TRUE, you’ll do whatever is appropriate as a response to the event, and when it returns FALSE you’ll do nothing. If the event is an activate or update event for a dialog window, DialogSelect activates or updates the window and returns FALSE. If the event is a mouse-down event in an editText item, DialogSelect responds as appropriate (displaying a caret at the insertion point or selecting text). If it’s a key-down or auto-key event and there’s an editText item, text entry and editing are handled in the standard way. In either case, DialogSelect returns TRUE if the editText item is enabled or FALSE if it’s disabled. If a key-down or auto-key event is passed when there’s no editText item, DialogSelect returns FALSE. Note: For a keyboard event, DialogSelect doesn’t check to see whether the Command key is held down; to handle keyboard equivalents of commands, you have to check for them before calling DialogSelect. Similarly, to treat a typed character in a special way (such as ignore it, or make it have the same effect as another character or as clicking a button), you need to check for a key-down event with that character before calling DialogSelect. If the event is a mouse-down event in a control, DialogSelect calls the Control Manager function TrackControl. If the mouse button is released inside the control and the control is enabled, DialogSelect returns TRUE; otherwise, it returns FALSE. If the event is a mouse-down event in any other enabled item, DialogSelect returns TRUE. If it’s a mouse-down event in any other disabled item or in no item, or if it’s any other event, DialogSelect returns FALSE. Note: If the event isn’t one that DialogSelect specifically checks for (if it’s a null event, for example), and there’s an editText item in the dialog, DialogSelect calls the TextEdit procedure TEIdle to make the caret blink. æKY DrawDialog æFp Dialogs.p æT PROCEDURE æTN A981 æD PROCEDURE DrawDialog(theDialog: DialogPtr); INLINE $A981; æDT DrawDialog(theDialog); æMM æRI I-418 æC DrawDialog draws the contents of the given dialog box. Since DialogSelect and ModalDialog handle dialog window updating, this procedure is useful only in unusual situations. You would call it, for example, to display a dialog box that doesn’t require any response but merely tells the user what’s going on during a time-consuming process. æKY UpdtDialog æFp Dialogs.p æT PROCEDURE æTN A978 æD PROCEDURE UpdtDialog(theDialog: DialogPtr;updateRgn: RgnHandle); INLINE $A978; æDT UpdtDialog(theDialog,updateRgn); æMM æRI IV-60 æC UpdtDialog is a faster version of the DrawDialog procedure. Instead of drawing the entire contents of the given dialog box, UpdtDialog draws only the items that are in a specified update region. UpdtDialog is called in response to an update event, and is usually bracketed by calls to the Window Manager procedures BeginUpdate and EndUpdate. UpdateRgn should be set to the visRgn of theWindow’s port. (For more details, see the BeginUpdate procedure in the Window Manager chapter.) æKY Alert æFp Dialogs.p æT FUNCTION æTN A985 æD FUNCTION Alert(alertID: INTEGER;filterProc: ProcPtr): INTEGER; INLINE $A985; æDT myVariable := Alert(alertID,filterProc); æMM æRI I-418, V-284 æC This function invokes the alert defined by the alert template that has the given resource ID. It calls the current sound procedure, if any, passing it the sound number specified in the alert template for this stage of the alert. If no alert box is to be drawn at this stage, Alert returns a function result of –1; otherwise, it creates and displays the alert window for this alert and draws the alert box. Warning: If the alert template resource can’t be read, the function result is undefined. Note: Alert creates the alert window by calling NewDialog, and does the rest of its processing by calling ModalDialog. Alert repeatedly gets and handles events in the alert window until an enabled item is clicked, at which time it returns the item number. Normally you’ll then do whatever is appropriate in response to a click of that item. Alert gets each event by calling the Toolbox Event Manager function GetNextEvent. If the event is a mouse-down event outside the content region of the alert window, Alert emits sound number 1 (which should be a single beep) and gets the next event; otherwise, it filters and handles the event as described below. The filterProc parameter has the same meaning as in ModalDialog (see above). If it’s NIL, the standard filterProc function is executed, which makes the Return key or the Enter key have the same effect as clicking the default button. If you specify your own filterProc function and want to retain this feature, you must include it in your function. You can find out what the current default button is by looking at the aDefItem field of the dialog record for the alert (via the dialog pointer passed to the function). Alert handles the events for which the filterProc function returns FALSE as follows: • If the mouse button is pressed in a control, Alert calls the Control Manager procedure TrackControl. If the mouse button is released inside the control and the control is enabled, Alert returns; otherwise, it does nothing. • If the mouse button is pressed in any other enabled item, Alert simply returns. If it’s pressed in any other disabled item or in no item, or if any other event occurs, Alert does nothing. Before returning to the application with the item number, Alert removes the alert box from the screen. (It disposes of the alert window and its associated data structures, the item list, and the items.) Note: When an alert is removed, if it was overlapping the default button of a previous alert, that button’s bold outline won’t be redrawn. Note: The Alert function’s removal of the alert box would not be the desired result if the user clicked a check box or radio button; however, normally alerts contain only static text, icons, pictures, and buttons that are supposed to make the alert box go away. If your alert contains other items besides these, consider whether it might be more appropriate as a dialog. The Alert function looks for a resource of type 'actb' with the same ID as the alert. The alert color table is copied before it is passed to SetWinSize unless its ctSize field is equal to –1, indicating that the default window colors are to be used instead. The copy is made so that the color table resource can be purged without affecting the alert. The color dialog item list resource is duplicated as well, so it can be purgeable. æKY StopAlert æFp Dialogs.p æT FUNCTION æTN A986 æD FUNCTION StopAlert(alertID: INTEGER;filterProc: ProcPtr): INTEGER; INLINE $A986; æDT myVariable := StopAlert(alertID,filterProc); æMM æRI I-419, V-284, P-109, 182 æC StopAlert is the same as the Alert function (above) except that before drawing the items of the alert in the alert box, it draws the Stop icon in the top left corner of the box (within the rectangle (10,20)(42,52)). The Stop icon has the following resource ID: CONST stopIcon = 0; If the application’s resource file doesn’t include an icon with that ID number, the Dialog Manager uses the standard Stop icon in the system resource file (see Figure 11). The calls CautionAlert, StopAlert, and NoteAlert look for a resource of type 'actb' with the same ID as the alert. •••Refer to Figure 11.••• Figure 11–Standard Alert Icons æKY NoteAlert æFp Dialogs.p æT FUNCTION æTN A987 æD FUNCTION NoteAlert(alertID: INTEGER;filterProc: ProcPtr): INTEGER; INLINE $A987; æDT myVariable := NoteAlert(alertID,filterProc); æMM æRI I-420 æC NoteAlert is like StopAlert except that it draws the Note icon, which has the following resource ID: CONST noteIcon = 1; The calls CautionAlert, StopAlert, and NoteAlert look for a resource of type 'actb' with the same ID as the alert. æKY CautionAlert æFp Dialogs.p æT FUNCTION æTN A988 æD FUNCTION CautionAlert(alertID: INTEGER;filterProc: ProcPtr): INTEGER; INLINE $A988; æDT myVariable := CautionAlert(alertID,filterProc); æMM æRI I-420 æC CautionAlert is like StopAlert except that it draws the Caution icon, which has the following resource ID: CONST cautionIcon = 2; The calls CautionAlert, StopAlert, and NoteAlert look for a resource of type 'actb' with the same ID as the alert. æKY CouldAlert æFp Dialogs.p æT PROCEDURE æTN A989 æD PROCEDURE CouldAlert(alertID: INTEGER); INLINE $A989; æDT CouldAlert(alertID); æMM æRI I-420, V-285 æC CouldAlert makes the alert template having the given resource ID unpurgeable (reading it into memory if it’s not already there). It does the same for the alert window’s definition function, the alert’s item list resource, and any items defined as resources. This is useful if the alert may occur when the resource file isn’t accessible, such as during a disk copy. Warning: Like CouldDialog, CouldAlert assumes your alerts use the system font; if you’ve changed the font with SetDAFont, calling CouldAlert doesn’t make the font unpurgeable. The CouldAlert routine makes the alert color table template unpurgeable (reading it into memory if it isn’t already there), if it exists. It does the same for the alert’s color item list, if it has one. Warning: Like CouldDialog, CouldAlert doesn’t load or make 'FONT' or 'FOND' resources indicated in the color item list unpurgeable. æKY FreeAlert æFp Dialogs.p æT PROCEDURE æTN A98A æD PROCEDURE FreeAlert(alertID: INTEGER); INLINE $A98A; æDT FreeAlert(alertID); æMM æRI I-420, V-285 æC Given the resource ID of an alert template previously specified in a call to CouldAlert, FreeAlert undoes the effect of CouldAlert (by making the resources purgeable). It should be called when there’s no longer a need to keep the resources in memory. Given the resource ID of an alert template previously specified in a call to CouldAlert, the FreeAlert routine undoes the effect of CouldAlert, by restoring the original purge state of the color table and color item list resources. æKY GetDItem æFp Dialogs.p æT PROCEDURE æTN A98D æD PROCEDURE GetDItem(theDialog: DialogPtr;itemNo: INTEGER;VAR itemType: INTEGER; VAR item: Handle;VAR box: Rect); INLINE $A98D; æDT GetDItem(theDialog,itemNo,itemType,item,box); æMM æRI I-421 æC GetDItem returns in its VAR parameters the following information about the item numbered itemNo in the given dialog’s item list: In the itemType parameter, the item type; in the item parameter, a handle to the item (or, for item type userItem, the procedure pointer); and in the box parameter, the display rectangle for the item. Suppose, for example, that you want to change the title of a control in a dialog box. You can get the item handle with GetDItem, coerce it to type ControlHandle, and call the Control Manager procedure SetCTitle to change the title. Similarly, to move the control or change its size, you would call MoveControl or SizeControl. Note: To access the text of a statText or editText item, you can pass the handle returned by GetDItem to GetIText or SetIText (see below). æKY SetDItem æFp Dialogs.p æT PROCEDURE æTN A98E æD PROCEDURE SetDItem(theDialog: DialogPtr;itemNo: INTEGER;itemType: INTEGER; item: Handle;box: Rect); INLINE $A98E; æDT SetDItem(theDialog,itemNo,itemType,item,box); æMM æRT 34 æRI I-421, N34-1 æC SetDItem sets the item numbered itemNo in the given dialog’s item list, as specified by the parameters (without drawing the item). The itemType parameter is the item type; the item parameter is a handle to the item (or, for item type userItem, the procedure pointer); and the box parameter is the display rectangle for the item. Consider, for example, how to install an item of type userItem in a dialog: In the item list in the resource file, define an item in which the type is set to userItem and the display rectangle to (0,0)(0,0). Specify that the dialog window be invisible (in either the dialog template or the NewDialog call). After creating the dialog, coerce the item’s procedure pointer to type Handle; then call SetDItem, passing that handle and the display rectangle for the item. Finally, call the Window Manager procedure ShowWindow to display the dialog window. Note: Do not use SetDItem to change the text of a statText or editText item or to change or move a control. See the description of GetDItem above for more information. æKY HideDItem æFp Dialogs.p æT PROCEDURE æTN A827 æD PROCEDURE HideDItem(theDialog: DialogPtr;itemNo: INTEGER); INLINE $A827; æDT HideDItem(theDialog,itemNo); æMM æRI IV-59 æC HideDItem hides the item numbered itemNo in the given dialog’s item list by giving the item a display rectangle that’s off the screen. (Specifically, if the left coordinate of the item’s display rectangle is less than 8192, ShowDItem adds 16384 to both the left and right coordinates the rectangle.) If the item is already hidden (that is, if the left coordinate is greater than 8192), HideDItem does nothing. HideDItem calls the EraseRect procedure on the item’s enclosing rectangle and adds the rectangle that contained the item (not necessarily the item’s display rectangle) to the update region. If the specified item is an active editText item, the item is first deactivated (by calling TEDeactivate). Note: If you have items that are close to each other, be aware that the Dialog Manager draws outside of the enclosing rectangle by 3 pixels for editText items and by 4 pixels for a default button. An item that’s been hidden by HideDItem can be redisplayed by the ShowDItem procedure. Note: To create a hidden item in a dialog item list, simply add 16384 to the left and right coordinates of the display rectangle. æKY ShowDItem æFp Dialogs.p æT PROCEDURE æTN A828 æD PROCEDURE ShowDItem(theDialog: DialogPtr;itemNo: INTEGER); INLINE $A828; æDT ShowDItem(theDialog,itemNo); æMM æRI IV-59 æC ShowDItem redisplays the item numbered itemNo, previously hidden by HideDItem, by giving the item the display rectangle it had prior to the HideDItem call. (Specifically, if the left coordinate of the item’s display rectangle is greater than 8192, ShowDItem subtracts 16384 from both the left and right coordinates of the rectangle.) If the item is already visible (that is, if the left coordinate is less than 8192), ShowDItem does nothing. ShowDItem adds the rectangle that contained the item (not necessarily the item’s display rectangle) to the update region so that it will be drawn. If the item becomes the only editText item, ShowDItem activates it (by calling TEActivate). æKY SelIText æFp Dialogs.p æT PROCEDURE æTN A97E æD PROCEDURE SelIText(theDialog: DialogPtr;itemNo: INTEGER;strtSel: INTEGER; endSel: INTEGER); INLINE $A97E; æDT SelIText(theDialog,itemNo,strtSel,endSel); æMM æRI I-422, P-110 æC Given a pointer to a dialog and the item number of an editText item in the dialog box, SelIText does the following: • If the item contains text, SelIText sets the selection range to extend from character position strtSel up to but not including character position endSel. The selection range is inverted unless strtSel equals endSel, in which case a blinking vertical bar is displayed to indicate an insertion point at that position. • If the item doesn’t contain text, SelIText simply displays the insertion point. For example, if the user makes an unacceptable entry in the editText item, the application can put up an alert box reporting the problem and then select the entire text of the item so it can be replaced by a new entry. (Without this procedure, the user would have to select the item before making the new entry.) Note: You can select the entire text by specifying 0 for strtSel and 32767 for endSel. For details about selection range and character position, see the TextEdit chapter. æKY GetIText æFp Dialogs.p æT PROCEDURE æTN A990 æD PROCEDURE GetIText(item: Handle;VAR text: Str255); INLINE $A990; æDT GetIText(item,text); æRT 18 æRI I-422, N18-2 æC Given a handle to a statText or editText item in a dialog box, as returned by GetDItem, GetIText returns the text of the item in the text parameter. (If the user typed more than 255 characters in an editText item, GetIText returns only the first 255.) æKY SetIText æFp Dialogs.p æT PROCEDURE æTN A98F æD PROCEDURE SetIText(item: Handle;text: Str255); INLINE $A98F; æDT SetIText(item,text); æMM æRI I-422 æC Given a handle to a statText or editText item in a dialog box, as returned by GetDItem, SetIText sets the text of the item to the specified text and draws the item. For example, suppose the exact content of a dialog’s text item cannot be determined until the application is running, but the display rectangle is defined in the resource file: Call GetDItem to get a handle to the item, and call SetIText with the desired text. æKY FindDItem æFp Dialogs.p æT FUNCTION æTN A984 æD FUNCTION FindDItem(theDialog: DialogPtr;thePt: Point): INTEGER; INLINE $A984; æDT myVariable := FindDItem(theDialog,thePt); æMM æRT 112 æRI IV-60, N112 æC FindDItem returns the item number of the item containing the point specified, in local coordinates, by thePt. If the point doesn’t lie within the item’s rectangle, FindDItem returns –1. If there are overlapping items, it returns the item number of the first item in the list containing the point. FindDItem is useful for changing the cursor when it’s over a particular item. Note: FindDItem will return the item number of disabled items as well. æKY NewCDialog æFp Dialogs.p æT FUNCTION æTN AA4B æD FUNCTION NewCDialog(dStorage: Ptr;boundsRect: Rect;title: Str255;visible: BOOLEAN; procID: INTEGER;behind: WindowPtr;goAwayFlag: BOOLEAN;refCon: LONGINT; items: Handle): DialogPtr; INLINE $AA4B; æDT myVariable := NewCDialog(dStorage,boundsRect,title,visible,procID,behind,goAwayFlag,refCon,items); æMM æRI V-283 æC A new Dialog Manager routine has been added to support color dialogs: NewCDialog. Its parameters are identical to NewDialog, except that a cGrafPort is allocated through a NewCWindow call instead of a call to NewWindow. NewCDialog creates a dialog box as specified by its parameters and returns a cDialogPtr to the new dialog. The first eight parameters (dStorage through refCon) are passed to the Window Manager function NewCWindow, which creates the dialog window. The items parameter is a handle to the dialog’s item list. You can get the items handle by calling the Resource Manager to read the item list from the resource file into memory. After calling NewCDialog, you can use SetWinColor to add a color table to the dialog. This creates an auxiliary window record (auxWinRec) for the dialog window. You can access this record with the GetAuxWin routine. The dialogCItem handle within the auxWinRec points to the dialog item color table. If the dialog’s content color isn’t white, it’s a good idea to call NewCDialog with the visible flag set to FALSE. After the color table and color item list are installed, use ShowWindow to display the dialog if the dialog is the frontmost window. If the dialog is not in front, use ShowHide to display the dialog. æKY GetAlrtStage æFp Dialogs.p æT FUNCTION æD FUNCTION GetAlrtStage: INTEGER; INLINE $3EB8,$0A9A; æDT myVariable := GetAlrtStage(paramList); æRI I-422 æC GetAlrtStage returns the stage of the last occurrence of an alert, as a number from 0 to 3. Assembly-language note: Assembly-language programmers can get this number by accessing the global variable ACount. In addition, the global variable ANumber contains the resource ID of the alert template of the last alert that occurred. æKY ResetAlrtStage æFp Dialogs.p æT PROCEDURE æD PROCEDURE ResetAlrtStage; INLINE $4278,$0A9A; { ResetAlrtStage resets the stage of the last occurrence of an alert so that the next occurrenct of the same alert will be treatd as its first stage. This is useful, for example, when you've used ParamText to change the text of an alert such that from the user's point of view it's a different alert. } æDT ResetAlrtStage(paramList); æRI I-423 æC ResetAlrtStage resets the stage of the last occurrence of an alert so that the next occurrence of that same alert will be treated as its first stage. This is useful, for example, when you’ve used ParamText to change the text of an alert such that from the user’s point of view it’s a different alert. Assembly-language note: Assembly-language programmers can set the global variable ACount to –1 for the same effect. æKY DlgCut æFp Dialogs.p æT PROCEDURE æD PROCEDURE DlgCut(theDialog: DialogPtr); æDT DlgCut(theDialog); æRT 215 æRI I-418, P-110 æC [Not in ROM] DlgCut checks whether theDialog has any editText items and, if so, applies the TextEdit procedure TECut to the currently selected editText item. (If the dialog record’s editField is 0 or greater, DlgCut passes the contents of the textH field to TECut.) You can call DlgCut to handle the editing command Cut when a modeless dialog window is active. Assembly-language note: Assembly-language programmers can just read the dialog record’s fields and call TextEdit directly. æKY DlgPaste æFp Dialogs.p æT PROCEDURE æD PROCEDURE DlgPaste(theDialog: DialogPtr); æDT DlgPaste(theDialog); æMM æRT 215 æRI I-418, P-110 æC [Not in ROM] DlgPaste is the same as DlgCut (above) except that it calls TEPaste, for handling the Paste command. æKY DlgCopy æFp Dialogs.p æT PROCEDURE æD PROCEDURE DlgCopy(theDialog: DialogPtr); æDT DlgCopy(theDialog); æMM æRT 215 æRI I-418, P-110 æC [Not in ROM] DlgCopy is the same as DlgCut (above) except that it calls TECopy, for handling the Copy command. æKY DlgDelete æFp Dialogs.p æT PROCEDURE æD PROCEDURE DlgDelete(theDialog: DialogPtr); æDT DlgDelete(theDialog); æMM æRT 215 æRI I-418, P-110 æC [Not in ROM] DlgDelete is the same as DlgCut (above) except that it calls TEDelete, for handling the Clear command. æKY SetDAFont æFp Dialogs.p æT PROCEDURE æD PROCEDURE SetDAFont(fontNum: INTEGER); æDT SetDAFont(fontNum); æRI I-412 æC For subsequently created dialogs and alerts, SetDAFont causes the font of the dialog or alert window’s grafPort to be set to the font having the specified font number. If you don’t call this procedure, the system font is used. SetDAFont affects statText and editText items but not titles of controls, which are always in the system font. Assembly-language note: Assembly-language programmers can simply set the global variable DlgFont to the desired font number. æKY DisAsmLookup.p æKL Disassembler endOfModule InitLookup Lookup LookupTrapName ModifyOperand showMacsBugSymbol validMacsBugSymbol DisAsmStr80 LookupRegs _A0_ _A1_ _A2_ _A3_ _A4_ _A5_ _A6_ _A7_ _ABS_ _PC_ _TRAP_ æKY DisAsmStr80 æFp DisAsmLookup.p æT TYPE æD DisAsmStr80 = String[80]; æKY Disassembler æFp DisAsmLookup.p æT PROCEDURE æD PROCEDURE Disassembler(DstAdjust: LONGINT;VAR BytesUsed: INTEGER;FirstByte: UNIV Ptr; VAR Opcode: UNIV DisAsmStr80;VAR Operand: UNIV DisAsmStr80;VAR Comment: UNIV DisAsmStr80; LookUpProc: UNIV Ptr); æDT Disassembler(DstAdjust,BytesUsed,FirstByte,Opcode,Operand,Comment,LookUpProc); æC (* Disassembler is a Pascal routine to be called to disassemble a sequence of bytes. All MC68xxx, MC68881, and MC68851 instructions are supported. The sequence of bytes to be disassembled are pointed to by FirstByte. BytesUsed bytes starting at FirstByte are consumed by the disassembly, and the Opcode, Operand, and Comment strings returned as NULL TERMINATED Pascal strings (for easier manipulation with C). The caller is then free to format or use the output strings any way appropriate to the application. Depending on the opcode and effective address(s) (EA's) to be disassembled, the Opcode, Operand, and Comment strings contain the following information: Case Opcode Operand Comment ======================================================================= Non PC-relative EA's op.sz EA's PC-relative EA's op.sz EA's ; address Toolbox traps DC.W $AXXX ; TB XXXX OS traps DC.W $AXXX ; OS XXXX Invalid bytes DC.W $XXXX ; ???? Invalid byte #immediate DC.W $XXXX,... ; op.sz #$??XX,EA ======================================================================= For valid disassembly of processor instructions the appropriate MC68XXX opcode mnemonic is generated for the Opcode string along with a size attribute when required. The source and destination EA's are generated as the Operand along with a possible comment. Comments start with a ';'. Traps use a DC.W assembler directive as the Opcode with the trap word as the Operand and a comment indicating whether the trap is a toolbox or OS trap and what the trap number is. As described later the caller can generate symbolic substitutions into EA's and provide names for traps. Invalid instructions cause the string 'DC.W' to be returned in the Opcode string. Operand is '$XXXX' (the invalid word) with a comment of '; ????'. BytesUsed is 2. This is similar to the trap call case except for the comment. A special case is made for immediate byte operands with a nonzero high order byte. For example, the bytes $020011FF, when actually executed, would be interpreted as ANDI.B $FF,D0. The processor will IGNORE the high order byte of the immediate data! Thus, the bytes may be considered as valid. Since the Disassembler has no way of knowing the context in which it is disassembling, it returns the Opcode as 'DC.W' as in the normal invalid case. However, the Operand string shows ALL the words disassembled separated with commas and places the possibly valid disassembly in the Operand's comment indicating the nonzero bytes. Thus for the example $020011FF bytes, the Opcode will be 'DC.W', the Operand will be '$0200,$11FF', and the Comment '; ANDI.B #$??FF,D0'. BytesUsed in this case would be 4. Note, the Operand EA's is syntatically similar to but NOT COMPATIBLE with the MPW assembler! This is because the Disassembler generates byte hex constants as "$XX" and word hex constants as "$XXXX". Negative values (e.g., $FF or $FFFF) produced by the Disassembler are treated as long word values by the MPW assembler. Thus it is assumed that Disassembler output will NOT be used as MPW assembler input. If that is the goal, then the caller must convert strings of the form $XX or $XXXX in the Operand string to their decimal equivalent. The routine ModifyOperand is provided in this unit to aid with the conversion process. Since a PC-relative comment is an address, the only address that the Disassembler knows about is the address of the code pointed to by FirstByte. Generally, that may be a buffer that has no relation to "reality", i.e., the actual code loaded into the buffer. Therefore, to allow the address comment to be mapped back to some actual address the caller may specify an adjustment factor, specified by DstAdjust that is ADDED to the value that normally would be placed in the comment. Operand effective address strings are generated as a function of the effective address mode and a special case is made for A-trap opcode strings. In places where a possible symbolic reference could be substituted for an address (or a portion of an address), the Disassembler can call a user specified routine to do the substitution (using th LookupProc parameter described later). The following table summarizes the generated effective addresses and where symbolic substitutions (S) can be made: Mode Generated Effective Address Effective Address with Substitution ======================================================================== 0 Dn Dn 1 An An 2 (An) (An) 3 (An)+ (An)+ 4 -(An) -(An) 5 ∂(An) S(An) or just S (if An=A5, ∂≥0) 6n ∂(An,Xn.Size*Scale) S(An,Xn.Size*Scale) 6n (BD,An,Xn.Size*Scale) (S,An,Xn.Size*Scale) 6n ([BD,An],Xm.Size*Scale,OD) ([S,An],Xm.Size*Scale,OD) 6n ([BD,An,Xn.Size*Scale],OD) ([S,An,Xn.Size*Scale],OD) 70 ∂ S 71 ∂ S 72 *±∂ S 73 *±∂(Xn.Size*Scale) S(Xn.Size*Scale) 73 (*±∂,Xn.Size*Scale) (S,Xn.Size*Scale) 73 ([*±∂],Xm.Size*Scale,OD) ([S],Xm.Size*Scale,OD) 73 ([*±∂,Xn.Size*Scale],OD) ([S,Xn.Size*Scale],OD) 74 #data #data ======================================================================== For A-traps, the substitution can be performed to substitute for the DC.W opcode string. If the substitution is made then the Disassembler will generate ,Sys and/or ,Immed flags as operands for Toolbox traps and ,AutoPop for OS traps when the bits in the trap word indicates these settings. | Generated | Substituted | Opcode Operand Comment | Opcode Operand Comment ======================================================================== Toolbox | DC.W $AXXX ; TB XXXX | S [,Sys][,Immed] ; AXXX OS | DC.W $AXXX ; OS XXXX | S [,AutoPop] ; AXXX ======================================================================== All displacements (∂, BD, OD) are hexadecimal values shown as a byte ($XX), word ($XXXX), or long ($XXXXXXXX) as appropriate. The *Scale is suppressed if 1. The Size is W or L. Note that effective address substitutions can only be made for "∂(An)", "BD,An", and "*±∂" cases. For all the effective address modes 5, 6n, 7n, and for A-traps, a coroutine (a procedure) whose address is specified by the LookupProc parameter is called by the Disassembler (if LookupProc is not NIL) to do the substitution (or A-trap comment) with a string returned by the proc. It is assumed that the proc pointed to by LookupProc is a level 1 Pascal proc declared as follows: PROCEDURE Lookup( PC: UNIV Ptr; {Addr of extension/trap word} BaseReg: LookupRegs; {Base register/lookup mode } Opnd: UNIV LongInt; {Trap word, PC addr, disp. } VAR S: DisAsmStr80); {Returned substitution } where TYPE DisAsmStr80 = String[80]; or in C, pascal void LookUp(Ptr PC, LookupRegs BaseReg, long Opnd, char *S); PC = Pointer to instruction extension word or A-trap word in the buffer pointed to by the Disassembler's FirstByte parameter. BaseReg = This determines the meaning of the Opnd value and supplies the base register for the "∂(An)", "BD,An", and "*±∂" cases. BaseReg may contain any one of the following values: _A0_ = 0 ==> A0 _A1_ = 1 ==> A1 _A2_ = 2 ==> A2 _A3_ = 3 ==> A3 _A4_ = 4 ==> A4 _A5_ = 5 ==> A5 _A6_ = 6 ==> A6 _A7_ = 7 ==> A7 _PC_ = 8 ==> PC-relative (special case) _ABS_ = 9 ==> Abs addr (special case) _TRAP_ = 10 ==> Trap word (special case) For absolute addressing (modes 70 and 71), BaseReg contains _ABS_. For A-traps, BaseReg would contain _TRAP_. Opnd = The contents of this LongInt is determined by the BaseReg parameter just described. For BaseReg = _TRAP_ (A-traps): Opnd is the entire trap word. The high order 16 bits of Opnd are zero. For BaseReg = _ABS_ (absolute effective address): Opnd contains the (extended) 32-bit address specifed by the instruction's effective address. Such addresses would generally be used to reference low memory globals on a Macintosh. For BaseReg = _PC_ (PC-relative effective address): Opnd contains the 32-bit address represented by "*±∂" adjusted by the Disassembler's DstAdjust parameter. For BaseReg = _An_ (effective address with a base register): Opnd contains the (sign-extended) 32-bit (base) displacement from the instruction's effective address. In the Macintosh environment, a BaseReg specifying A5 implies either global data references or Jump Table references. Positive Opnd values with an A5 BaseReg thus mean Jump Table references, while a negative offset would mean a global data reference. Base registers of A6 or A7 would usually mean local data. S = Pascal string returned from Lookup containing the effective address substitution string or a trap name for A-traps. S is set to null PRIOR to calling Lookup. If it is still null on return, the string is not used. If not null, then for A-traps, the returned string is used as a opcode string. In all other cases the string is substituted as shown in the above table. Depending on the application, the caller has three choices on how to use the Disassembler and an associated Lookup proc: (1). The caller can call just the Disassembler and provide his own Lookup proc. In that case the calling conventions discussed above must be followed. (2). The caller can provide NIL for the LookupProc parameter, in which case, NO Lookup proc will be called. (3). The caller can call first InitLookup (described below, a proc provided with this unit) and pass the address of this unit's standard Lookup proc when Disassembler is called. In this case all the control logic to determine the kind of substitution to be done is provided for the caller and all that need to be provided by the user are routines to look up any or all of the following: • PC-relative references • Jump Table references • Absolute address references • Trap names • References with offsets from base registers *) æKY endOfModule æFp DisAsmLookup.p æT FUNCTION æD FUNCTION endOfModule(address: UNIV Ptr;limit: UNIV Ptr;symbol: StringPtr; VAR nextModule: UNIV Ptr): StringPtr; C; æDT myVariable := endOfModule(address,limit,symbol,nextModule); æC { Check to see if the specified memory address contains a RTS, JMP (A0) or RTD #n instruction immediately followed by a valid MacsBug symbol. These sequences are the only ones which can determine an end of module when MacsBug symbols are present. During the check, the instruction and its following MacsBug symbol must be fully contained in the bytes starting at the specified address parameter, up to, but not including, the byte pointed to by the limit parameter. If the end of module is NOT found, then NULL is returned as the function's result. However, if a end of module is found, the MacsBug symbol is returned in symbol (if it is not NULL) as a null terminated Pascal string (with trailing blanks removed), and the functions returns the pointer to the start of the MacsBug symbol (i.e., address+2 for RTS or JMP (A0) and address+4 for RTD #n). This address may then be used as in input parameter to showMacsBugSymbol to convert the MacsBug symbol to a Disassembler operand string. Also returned in nextModule is where we think the FOLLOWING module begins. In the "old style" cases (see validMacsBugSymbol) this will always be 8 or 16 bytes after the input address. For new style the Apple Pascal and C cases this will depend on the symbol length, existence of a pad byte, and size of the constant (literal) area. See validMacsBugSymbol for a description of valid MacsBug symbol formats. } æKY InitLookup æFp DisAsmLookup.p æT PROCEDURE æD PROCEDURE InitLookup(PCRelProc: UNIV Ptr;JTOffProc: UNIV Ptr;TrapProc: UNIV Ptr; AbsAddrProc: UNIV Ptr;IdProc: UNIV Ptr); æDT InitLookup(PCRelProc,JTOffProc,TrapProc,AbsAddrProc,IdProc); æC { Prepare for use of this unit's Lookup proc. When Disassembler is called and the address of this unit's Lookup proc is specified, then for PC-relative, Jump Table references, A-traps, absolute addresses, and offsets from a base register, the associated level 1 Pascal proc specified here is called (if not NULL -- all five addresses are preset to NULL). The calls assume the following declarations for these procs (see Lookup, below for further details): PROCEDURE PCRelProc(Address: UNIV LongInt; VAR S: UNIV DisAsmStr80); PROCEDURE JTOffProc(A5JTOffset: UNIV Integer; VAR S: UNIV DisAsmStr80); PROCEDURE TrapNameProc(TrapWord: UNIV Integer; VAR S: UNIV DisAsmStr80); PROCEDURE AbsAddrProc(AbsAddr: UNIV LongInt; VAR S: UNIV DisAsmStr80); PROCEDURE IdProc(BaseReg: LookupRegs; Offset: UNIV LongInt; VAR S: UNIV DisAsmStr80); or in C, pascal void PCRelProc(long Address, char *S) pascal void JTOffProc(short A5JTOffset, char *S) pascal void TrapNameProc(unsigned short TrapWord, char *S) pascal void AbsAddrProc(long AbsAddr, char *S) pascal void IdProc(LookupRegs BaseReg, long Offset, char *S) Note: InitLookup contains initialized data which requires initializing at load time (this is of concern only to users with assembler main programs. } æKY Lookup æFp DisAsmLookup.p æT PROCEDURE æD PROCEDURE Lookup(PC: UNIV Ptr;BaseReg: LookupRegs;Opnd: UNIV LongInt; VAR S: DisAsmStr80); æDT Lookup(PC,BaseReg,Opnd,S); æC { This is a standard Lookup proc available to the caller for calls to the Disassembler. If the caller elects to use this proc, then InitLookup MUST be called prior to any calls to the Disassembler. All the logic to determine the type of lookup is done by this proc. For PC-relative, Jump Table references, A-traps, absolute addresses, and offsets from a base register, the associated level 1 Pascal proc specified in the InitLookup call (if not NULL) is called. This scheme simplifies the Lookup mechanism by allowing the caller to deal with just the problems related to the application. } æKY LookupRegs _A0_ _A1_ _A2_ _A3_ _A4_ _A5_ _A6_ _A7_ _PC_ _ABS_ _TRAP_ æFp DisAsmLookup.p æD LookupRegs = (_A0_,_A1_,_A2_,_A3_,_A4_,_A5_,_A6_,_A7_,_PC_,_ABS_,_TRAP_); æKY LookupTrapName æFp DisAsmLookup.p æT PROCEDURE æD PROCEDURE LookupTrapName(TrapWord: UNIV Integer;VAR S: UNIV DisAsmStr80); æDT LookupTrapName(TrapWord,S); æC { This is a procedure provided to allow conversion of a trap instruction (in TrapWord) to its corresponding trap name (in S). It is provided primarily for use with the Disassembler and its address may be passed to InitLookup above for use by this unit's Lookup routine. Alternatively, there is nothing prohibiting the caller from using it directly for other purposes or by some other lookup proc. Note: The tables in this proc make the size of this proc about 9500 bytes. The trap names are fully spelled out in upper and lower case. } æKY ModifyOperand æFp DisAsmLookup.p æT PROCEDURE æD PROCEDURE ModifyOperand(VAR Operand: UNIV DisAsmStr80); æDT ModifyOperand(Operand); æC { Scan an operand string, i.e., the null terminated Pascal string returned by the Disassembler (null MUST be present here) and modify negative hex values to negated positive value. For example, $FFFF(A5) would be modified to -$0001(A5). The operand to be processed is passed as the function's parameter which is edited "in place" and returned to the caller. This routine is essentially a pattern matcher and attempts to only modify 2, 4, and 8 digit hex strings in the operand that "might" be offsets from a base register. If the matching tests are passed, the same number of original digits are output (because that indicates a value's size -- byte, word, or long). For a hex string to be modified, the following tests must be passed: • There must have been exactly 2, 4, or 8 digits. Only hex strings $XX, $XXXX, and $XXXXXXXX are possible candidates because that is the only way the Disassembler generates offsets. • Hex string must be delimited by a "(" or a ",". The "(" allows offsets for $XXXX(An,...) and $XX(An,Xn) addressing modes. The comma allows for the MC68020 addressing forms. • The "$X..." must NOT be preceded by a "±". This eliminates the possibility of modifying the offset of a PC-relative addressing mode always generated in the form "*±$XXXX". • The "$X..." must NOT be preceded by a "#". This eliminates modifying immediate data. • Value must be negative. Negative values are the only values we modify. A value $FFFF is modified to -$0001. } æKY showMacsBugSymbol æFp DisAsmLookup.p æT FUNCTION æD FUNCTION showMacsBugSymbol(symStart: UNIV Ptr;limit: UNIV Ptr;operand: StringPtr; VAR bytesUsed: INTEGER): StringPtr; C; æDT myVariable := showMacsBugSymbol(symStart,limit,operand,bytesUsed); æC { Format a MacsBug symbol as a operand of a DC.B directive. The first one or two bytes of the symbol are generated as $80+'c' if they have there high high bits set. All other characters are shown as characters in a string constant. The pad byte, if present, is one is also shown as $00. This routine is called to check that the bytes pointed to by symStart represent a valid MacsBug symbol. The symbol must be fully contained in the bytes starting at symStart, up to, but not including the byte pointed to by the limit parameter. When called, showMacsBugSymbol assumes that symStart is pointing at a valid MacsBug symbol as validated by the validMacsBugSymbol or endOfModule routines. As with validMacsBugSymbol, the symbol must be fully contained in the bytes starting at symStart up to, but not including, the byte pointed to by the end parameter. The string is returned in the 'operand' parameter as a null terminated Pascal string. The function also returns a pointer to this string as its return value (NULL is returned only if the byte pointed to by the limit parameter is reached prior to processing the entire symbol -- which should not happen if properly validated). The number of bytes used for the symbol is returned in bytesUsed. Due to the way MacsBug symbols are encoded, bytesUsed may not necessarily be the same as the length of the operand string. A valid MacsBug symbol consists of the characters '_', '%', spaces, digits, and upper/lower case letters in a format determined by the first two bytes of the symbol as described in the validMacsBugSymbol routine. } æKY validMacsBugSymbol æFp DisAsmLookup.p æT FUNCTION æD FUNCTION validMacsBugSymbol(symStart: UNIV Ptr;limit: UNIV Ptr;symbol: StringPtr): StringPtr; C; æDT myVariable := validMacsBugSymbol(symStart,limit,symbol); æC { Check that the bytes pointed to by symStart represents a valid MacsBug symbol. The symbol must be fully contained in the bytes starting at symStart, up to, but not including, the byte pointed to by the limit parameter. If a valid symbol is NOT found, then NULL is returned as the function's result. However, if a valid symbol is found, it is copied to symbol (if it is not NULL) as a null terminated Pascal string, and return a pointer to where we think the FOLLOWING module begins. In the "old style" cases (see below) this will always be 8 or 16 bytes after the input symStart. For new style Apple Pascal and C cases this will depend on the symbol length, existence of a pad byte, and size of the constant (literal) area. In all cases, trailing blanks are removed from the symbol. A valid MacsBug symbol consists of the characters '_', '%', spaces, digits, and upper/lower case letters in a format determined by the first two bytes of the symbol as follows: 1st byte | 2nd byte | Byte | Range | Range | Length | Comments ============================================================================== $20 - $7F | $20 - $7F | 8 | "Old style" MacsBug symbol format $A0 - $FF | $20 - $7F | 8 | "Old style" MacsBug symbol format ------------------------------------------------------------------------------ $20 - $7F | $80 - $FF | 16 | "Old style" MacApp symbol ab==>b.a $A0 - $FF | $80 - $FF | 16 | "Old style" MacApp symbol ab==>b.a ------------------------------------------------------------------------------ $80 | $01 - $FF | n | n = 2nd byte (Apple Compiler symbol) $81 - $9F | $00 - $FF | m | m = 1st byte & $7F (Apple Compiler symbol) ============================================================================== The formats are determined by whether bit 7 is set in the first and second bytes. This bit will removed when we find it or'ed into the first and/or second valid symbol characters. The first two formats in the above table are the basic "old style" (pre- existing) MacsBug formats. The first byte may or may not have bit 7 set the second byte is a valid symbol character. The first byte (with bit 7 removed) and the next 7 bytes are assumed to comprise the symbol. The second pair of formats are also "old style" formats, but used for MacApp symbols. Bit 7 set in the second character indicates these formats. The symbol is assumed to be 16 bytes with the second 8 bytes preceding the first 8 bytes in the generated symbol. For example, 12345678abcdefgh represents the symbol abcdefgh.12345678. The last pair of formats are reserved by Apple and generated by the MPW Pascal and C compilers. In these cases the value of the first byte is always between $80 and $9F, or with bit 7 removed, between $00 and $1F. For $00, the second byte is the length of the symbol with that many bytes following the second byte (thus a max length of 255). Values $01 to $1F represent the length itself. A pad byte may follow these variable length cases if the symbol does not end on a word boundary. Following the symbol and the possible pad byte is a word containing the size of the constants (literals) generated by the compiler. Note that if symStart actually does point to a valid MacsBug symbol, then you may use showMacsBugSymbol to convert the MacsBug symbol bytes to a string that could be used as a DC.B operand for disassembly purposes. This string explicitly shows the MacsBug symbol encodings. } æKY DiskInit.p æKL DIBadMount DIFormat DILoad DIUnload DIVerify DIZero HFSDefaults æKY HFSDefaults æFp DiskInit.p æT RECORD æD HFSDefaults = RECORD sigWord: PACKED ARRAY [0..1] OF Byte; { signature word} abSize: LONGINT; { allocation block size in bytes} clpSize: LONGINT; { clump size in bytes} nxFreeFN: LONGINT; { next free file number} btClpSize: LONGINT; { B-Tree clump size in bytes} rsrv1: INTEGER; { reserved} rsrv2: INTEGER; { reserved} rsrv3: INTEGER; { reserved} END; æC »Formatting Hierarchical Volumes The Disk Initialization Package must set certain volume characteristics when placing a hierarchical file directory on a volume. Default values for these volume characteristics are stored in the 128K ROM; this section is for advanced programmers who want to substitute their own values. The record containing the default values, if defined in Pascal, would look like this: TYPE HFSDefaults = PACKED RECORD sigWord: ARRAY[1..2] OF CHAR; {signature word} abSize: LONGINT; {allocation block size in bytes} clpSize: LONGINT; {clump size in bytes} nxFreeFN: LONGINT; {next free file number} btClpSize: LONGINT; {B*-Tree clump size in bytes} rsrv1: INTEGER; {reserved} rsrv2: INTEGER; {reserved} rsrv3: INTEGER; {reserved} END; The default values for these fields are as follows: Field Default value sigWord 'BD' abSize 0 clpSize 4 * abSize nxFreeFN 16 btClpSize 0 To supply your own values for these fields, create a similar, nonrelocatable record containing the desired values and place a pointer to it in the global variable FmtDefaults. To restore the system defaults, simply clear FmtDefaults. The sigWord must equal 'BD' (meaning “big disk”) for the volume to be recognized as a hierarchical volume. If the specified allocation block size is 0, the allocation block size is calculated according to the size of the volume: abSize = (1 + (volSize in blocks / 64K)) * 512 bytes If the specified B*-tree clump size is 0, the clump size for both the catalog and extent trees is calculated according to the size of the volume: btClpSize = (volSize in blocks)/128 * 512bytes æKY DILoad æFp DiskInit.p æT PROCEDURE æD PROCEDURE DILoad; æDT DILoad(paramList); æMM æRI II-396 æC Assembly-language note: The trap macro for the Disk Initialization Package is _Pack2. The routine selectors are as follows: diBadMount .EQU 0 diLoad .EQU 2 diUnload .EQU 4 diFormat .EQU 6 diVerify .EQU 8 diZero .EQU 10 DILoad reads the Disk Initialization Package, and its associated dialog and dialog items, from the system resource file into memory and makes them unpurgeable. Note: DIFormat, DIVerify, and DIZero don’t need the dialog, so if you use only these routines you can call the Resource Manager function GetResource to read just the package resource into memory (and the Memory Manager procedure HNoPurge to make it unpurgeable). æKY DIUnload æFp DiskInit.p æT PROCEDURE æD PROCEDURE DIUnload; æDT DIUnload(paramList); æMM æRI II-396 æC Assembly-language note: The trap macro for the Disk Initialization Package is _Pack2. The routine selectors are as follows: diBadMount .EQU 0 diLoad .EQU 2 diUnload .EQU 4 diFormat .EQU 6 diVerify .EQU 8 diZero .EQU 10 DIUnload makes the Disk Initialization Package (and its associated dialog and dialog items) purgeable. æKY DIBadMount æFp DiskInit.p æT FUNCTION æD FUNCTION DIBadMount(where: Point;evtMessage: LONGINT): INTEGER; æDT myVariable := DIBadMount(where,evtMessage); æRI DIBadMount function II-396, N70-1, P-34, 168 æC Assembly-language note: The trap macro for the Disk Initialization Package is _Pack2. The routine selectors are as follows: diBadMount .EQU 0 diLoad .EQU 2 diUnload .EQU 4 diFormat .EQU 6 diVerify .EQU 8 diZero .EQU 10 Call DIBadMount when a disk-inserted event occurs if the result code in the high-order word of the associated event message indicates an error (that is, the result code is other than noErr). Given the event message in evtMessage, DIBadMount evaluates the result code and either ejects the disk or lets the user initialize and name it. The low-order word of the event message contains the drive number. The where parameter specifies the location (in global coordinates) of the top left corner of the dialog box displayed by DIBadMount. If the result code passed is extFSErr, memFullErr, nsDrvErr, paramErr, or volOnLinErr, DIBadMount simply ejects the disk from the drive and returns the result code. If the result code ioErr, badMDBErr, or noMacDskErr is passed, the error can be corrected by initializing the disk; DIBadMount displays a dialog box that describes the problem and asks whether the user wants to initialize the disk. For the result code ioErr, the dialog box shown in Figure 1 is displayed. (This happens if the disk is brand new.) For badMDBErr and noMacDskErr, DIBadMount displays a similar dialog box in which the description of the problem is “This disk is damaged” and “This is not a Macintosh disk”, respectively. •••Refer to Figure 1.••• Figure 1–Disk Initialization Dialog for IOErr Note: Before presenting the disk initialization dialog, DIBadMount checks whether the drive contains an already mounted volume; if so, it ejects the disk and returns 2 as its result. This will happen rarely and may reflect an error in your program (for example, you forgot to call DILoad and the user had to switch to the disk containing the system resource file). If the user responds to the disk initialization dialog by clicking the Eject button, DIBadMount ejects the disk and returns 1 as its result. If the Initialize button is clicked, a box displaying the message “Initializing disk...” appears, and DIBadMount attempts to initialize the disk. If initialization fails, the disk is ejected and the user is informed as shown in Figure 2; after the user clicks OK, DIBadMount returns a negative result code ranging from firstDskErr to lastDskErr, indicating that a low-level disk error occurred. •••Refer to Figure 2.••• Figure 2–Initialization Failure Dialog If the disk is successfully initialized, the dialog box in Figure 3 appears. After the user names the disk and clicks OK, DIBadMount mounts the volume by calling the File Manager function MountVol and returns MountVol’s result code (noErr if no error occurs). •••Refer to Figure 3.••• Figure 3–Dialog for Naming a Disk Result codes noErr No error extFSErr External file system memFullErr Not enough room in heap zone nsDrvErr No such drive paramErr Bad drive number volOnLinErr Volume already on-line firstDskErr Low-level disk error through lastDskErr Other results 1 User clicked Eject 2 Mounted volume in drive æKY DIFormat æFp DiskInit.p æT FUNCTION æD FUNCTION DIFormat(drvNum: INTEGER): OSErr; æDT myVariable := DIFormat(drvNum); æMM æRI II-398 æC Assembly-language note: The trap macro for the Disk Initialization Package is _Pack2. The routine selectors are as follows: diBadMount .EQU 0 diLoad .EQU 2 diUnload .EQU 4 diFormat .EQU 6 diVerify .EQU 8 diZero .EQU 10 DIFormat formats the disk in the drive specified by the given drive number and returns a result code indicating whether the formatting was completed successfully or failed. Formatting a disk consists of writing special information onto it so that the Disk Driver can read from and write to the disk. Result codes noErr No error firstDskErr Low-level disk error through lastDskErr æKY DIVerify æFp DiskInit.p æT FUNCTION æD FUNCTION DIVerify(drvNum: INTEGER): OSErr; æDT myVariable := DIVerify(drvNum); æMM æRI II-398 æC Assembly-language note: The trap macro for the Disk Initialization Package is _Pack2. The routine selectors are as follows: diBadMount .EQU 0 diLoad .EQU 2 diUnload .EQU 4 diFormat .EQU 6 diVerify .EQU 8 diZero .EQU 10 DIVerify verifies the format of the disk in the drive specified by the given drive number; it reads each bit from the disk and returns a result code indicating whether all bits were read successfully or not. DIVerify doesn’t affect the contents of the disk itself. Result codes noErr No error firstDskErr Low-level disk error through lastDskErr æKY DIZero æFp DiskInit.p æT FUNCTION æD FUNCTION DIZero(drvNum: INTEGER;volName: Str255): OSErr; æDT myVariable := DIZero(drvNum,volName); æMM æRT 70 æRI II-399, N70-2 æC Assembly-language note: The trap macro for the Disk Initialization Package is _Pack2. The routine selectors are as follows: diBadMount .EQU 0 diLoad .EQU 2 diUnload .EQU 4 diFormat .EQU 6 diVerify .EQU 8 diZero .EQU 10 On the unmounted volume in the drive specified by the given drive number, DIZero writes the volume information, a block map, and a file directory as for a volume with no files; the volName parameter specifies the volume name to be included in the volume information. This is the last step in initialization (after formatting and verifying) and makes any files that are already on the volume permanently inaccessible. If the operation fails, DIZero returns a result code indicating that a low-level disk error occurred; otherwise, it mounts the volume by calling the File Manager function MountVol and returns MountVol’s result code (noErr if no error occurs). Result codes noErr No error badMDBErr Bad master directory block extFSErr External file system ioErr I/O error memFullErr Not enough room in heap zone noMacDskErr Not a Macintosh disk nsDrvErr No such drive paramErr Bad drive number volOnLinErr Volume already on-line firstDskErr Low-level disk error through lastDskErr æKY Disks.p æKL DiskEject DriveStatus SetTagBuffer DriveKind DrvSts hard20 sony æKY DriveKind sony hard20 æFp Disks.p æT TYPE æD DriveKind = (sony,hard20); æC æKY DrvSts æFp Disks.p æT RECORD æD DrvSts = RECORD track: INTEGER; {current track} writeProt: SignedByte; {bit 7 = 1 if volume is locked} diskInPlace: SignedByte; {disk in drive} installed: SignedByte; {drive installed} sides: SignedByte; {-1 for 2-sided, 0 for 1-sided} driveQLink: QElemPtr; {next queue entry} driveQVers: INTEGER; {1 for HD20} dQDrive: INTEGER; {drive number} dQRefNum: INTEGER; {driver reference number} dQFSID: INTEGER; {file system ID} CASE DriveKind OF sony: (twoSideFmt: SignedByte; {after 1st rd/wrt: 0=1 side, -1=2 side} needsFlush: SignedByte; {-1 for MacPlus drive} diskErrs: INTEGER); {soft error count} hard20: (driveSize: INTEGER; {drive block size low word} driveS1: INTEGER; {drive block size high word} driveType: INTEGER; {1 for HD20} driveManf: INTEGER; {1 for Apple Computer, Inc.} driveChar: SignedByte; {230 ($E6) for HD20} driveMisc: SignedByte); {0 -- reserved} END; æC æKY DiskEject æFp Disks.p æT FUNCTION æD FUNCTION DiskEject(drvNum: INTEGER): OSErr; æDT myVariable := DiskEject(drvNum); æMM æRI II-214 æC [Not in ROM] Assembly-language note: DiskEject is equivalent to a Control call with csCode equal to the global constant ejectCode. DiskEject ejects the disk from the internal drive if drvNum is 1, or from the external drive if drvNum is 2. Result codes noErr No error nsDrvErr No such drive æKY SetTagBuffer æFp Disks.p æT FUNCTION æD FUNCTION SetTagBuffer(buffPtr: Ptr): OSErr; æDT myVariable := SetTagBuffer(buffPtr); æMM æRI II-214 æC [Not in ROM] Assembly-language note: SetTagBuffer is equivalent to a Control call with csCode equal to the global constant tgBuffCode. An application can change the information used in the file tags buffer by calling SetTagBuffer. The buffPtr parameter points to a buffer that contains the information to be used. If buffPtr is NIL, the information in the file tags buffer isn’t changed. If buffPtr isn’t NIL, every time the Disk Driver reads a sector from the disk, it stores the file tags in the file tags buffer and in the buffer pointed to by buffPtr. Every time the Disk Driver writes a sector onto the disk, it reads 12 bytes from the buffer pointed to by buffPtr, places them in the file tags buffer, and then writes them onto the disk. The contents of the buffer pointed to by buffPtr are overwritten at the end of every read request (which can be composed of a number of sectors) instead of at the end of every sector. Each read request places 12 bytes in the buffer for each sector, always beginning at the start of the buffer. This way an application can examine the file tags for a number of sequentially read sectors. If a read request is composed of a number of sectors, the Disk Driver places 12 bytes in the buffer for each sector. For example, for a read request of five sectors, the Disk Driver will place 60 bytes in the buffer. Result codes noErr No error æKY DriveStatus æFp Disks.p æT FUNCTION æD FUNCTION DriveStatus(drvNum: INTEGER;VAR status: DrvSts): OSErr; æDT myVariable := DriveStatus(drvNum,status); æMM æRI II-215 æC [Not in ROM] Assembly-language note: DriveStatus is equivalent to a Status call with csCode equal to the global constant drvStsCode; status is returned in csParam through csParam+21. DriveStatus returns information about the internal drive if drvNum is 1, or about the external drive if drvNum is 2. The information is returned in a record of type DrvSts: TYPE DrvSts = RECORD track: INTEGER; {current track} writeProt: SignedByte; {bit 7=1 if volume is locked} diskInPlace: SignedByte; {disk in place} installed: SignedByte; {drive installed} sides: SignedByte; {bit 7=0 if single-side drive} qLink: QElemPtr; {next queue entry} qType: INTEGER; {reserved for future use} dQDrive: INTEGER; {drive number} dQRefNum: INTEGER; {driver reference number} dQFSID: INTEGER; {file-system identifier} twoSideFmt: SignedByte; {-1 if two-sided disk} needsFlush: SignedByte; {reserved for future use} diskErrs: INTEGER {error count} END; The diskInPlace field is 0 if there’s no disk in the drive, 1 or 2 if there is a disk in the drive, or –4 to –1 if the disk was ejected in the last 1.5 seconds. The installed field is 1 if the drive is connected to the Macintosh, 0 if the drive might be connected to the Macintosh, and –1 if the drive isn’t installed. The value of twoSideFmt is valid only when diskInPlace=2. The value of diskErrs is incremented every time an error occurs internally within the Disk Driver. Result codes noErr No error nsDrvErr No such drive æKY Editions.p æKL AssociateSection CallEditionOpenerProc CallFormatIOProc CloseEdition CreateEditionContainerFile DeleteEditionContainerFile EditionHasFormat FindEditionContainerDialog GetEditionFormatMark GetEditionInfo GetEditionOpenerProc GetLastEditionContainerUsed GetStandardFormats GotoPublisherSection InitEditionPack IsRegisterSection NewPublisherDialog NewPublisherExpDialog NewSection NewSubscriberDialog NewSubscriberExpDialog OpenEdition OpenNewEdition ReadEdition RegisterSection SectionOptionsDialog SectionOptionsExpDialog SetEditionFormatMark SetEditionOpenerProc UnRegisterSection WriteEdition EditionContainerSpec EditionInfoRecord EditionOpenerParamBlock EditionOpenerVerb eoCanSubscribe eoClose eoCloseNew eoOpen eoOpenNew FormatIOParamBlock FormatIOVerb ioHasFormat ioNewFormat ioReadFormat ioWriteFormat kFormatLengthUnknown kFormatListFormat kPartNumberUnknown kPartsNotUsed kPreviewFormat kPreviewHeight kPreviewWidth kPublisherDocAliasFormat NewPublisherReply NewSubscriberReply pumOnSave pumSuspend rSectionType sectionCancelMsgID sectionEventMsgClass SectionHandle SectionOptionsReply SectionPtr sectionReadMsgID SectionRecord sectionScrollMsgID sectionWriteMsgID stPublisher stSubscriber sumAutomatic sumOnRequestOnly æKY rSectionType æFp Editions.p æT CONST æD { resource types } rSectionType = 'sect'; { ResType of saved SectionRecords } æC æKY stSubscriber æFp Editions.p æT CONST æD { ssection types } stSubscriber = $01; æC æKY stPublisher æFp Editions.p æT CONST æD stPublisher = $0A; æC æKY sumAutomatic æFp Editions.p æT CONST æD { update modes } sumAutomatic = 0; { subscriber update mode - Automatic } æC æKY sumOnRequestOnly æFp Editions.p æT CONST æD sumOnRequestOnly = 1; { subscriber update mode - OnRequestOnly } æC æKY pumOnSave æFp Editions.p æT CONST æD pumOnSave = 0; { publisher update mode - OnSave } æC æKY pumSuspend æFp Editions.p æT CONST æD pumSuspend = 1; { publisher update mode - OnRequestOnly } æC æKY kPartsNotUsed æFp Editions.p æT CONST æD kPartsNotUsed = 0; æC æKY kPartNumberUnknown æFp Editions.p æT CONST æD kPartNumberUnknown = (-1); æC æKY kPreviewWidth æFp Editions.p æT CONST æD kPreviewWidth = 120; æC æKY kPreviewHeight æFp Editions.p æT CONST æD kPreviewHeight = 120; æC æKY kPublisherDocAliasFormat æFp Editions.p æT CONST æD kPublisherDocAliasFormat = 'alis'; æC æKY kPreviewFormat æFp Editions.p æT CONST æD kPreviewFormat = 'prvw'; æC æKY kFormatListFormat æFp Editions.p æT CONST æD kFormatListFormat = 'fmts'; æC æKY kFormatLengthUnknown æFp Editions.p æT CONST æD kFormatLengthUnknown = (-1); æC æKY sectionEventMsgClass æFp Editions.p æT CONST æD { the following fields are private and set up by RegisterSection Section events now arrive in the message buffer using the new AppleEvent format. The direct object parameter is an aeTemporaryIDParamType ('tid '). The temporary ID's type is rSectionType ('sect') and the 32-bit value is a SectionHandle. } sectionEventMsgClass = 'sect'; æC æKY sectionReadMsgID æFp Editions.p æT CONST æD sectionReadMsgID = 'read'; æC æKY sectionWriteMsgID æFp Editions.p æT CONST æD sectionWriteMsgID = 'writ'; æC æKY sectionScrollMsgID æFp Editions.p æT CONST æD sectionScrollMsgID = 'scrl'; æC æKY sectionCancelMsgID æFp Editions.p æT CONST æD sectionCancelMsgID = 'cncl'; æC æKY FormatIOVerb ioHasFormat ioReadFormat ioNewFormat ioWriteFormat æFp Editions.p æT TYPE æD FormatIOVerb = (ioHasFormat,ioReadFormat,ioNewFormat,ioWriteFormat); æC æKY EditionOpenerVerb eoOpen eoClose eoOpenNew eoCloseNew eoCanSubscribe æFp Editions.p æT TYPE æD EditionOpenerVerb = (eoOpen,eoClose,eoOpenNew,eoCloseNew,eoCanSubscribe); æC æKY SectionRecord SectionPtr SectionHandle æFp Editions.p æT RECORD æD SectionPtr = ^SectionRecord; SectionHandle = ^SectionPtr; SectionRecord = RECORD version: SignedByte; { always 0x01 in system 7.0 } kind: SectionType; { stSubscriber or stPublisher } mode: UpdateMode; { auto or manual } mdDate: TimeStamp; { last change in document } sectionID: long; { app. specific, unique per document } refCon: long; { application specific } alias: AliasHandle; { handle to Alias Record } subPart: long; { which part of container file } nextSection: SectionHandle; { for linked list of app's Sections } controlBlock: Handle; { used internally } refNum: EdtionRefNum; { used internally } END; æC æKY EditionContainerSpec æFp Editions.p æT RECORD æD EditionContainerSpec = RECORD theFile: CanonicalFileSpec; theFileScript: short; thePart: long; thePartName: Str31; thePartScript: short; END; æC æKY EditionInfoRecord æFp Editions.p æT RECORD æD EditionInfoRecord = RECORD crDate: TimeStamp; { date EditionContainer was created } mdDate: TimeStamp; { date of last change } fdCreator: OSType; { file creator } fdType: OSType; { file type } container: EditionContainerSpec; { the Edition } END; æC æKY NewPublisherReply æFp Editions.p æT RECORD æD NewPublisherReply = RECORD canceled: Boolean; { O } replacing : Boolean; usePart: Boolean; { I } preview: Handle; { I } previewFormat: FormatType; { I } container: EditionContainerSpec; { I/O } END; æC æKY NewSubscriberReply æFp Editions.p æT RECORD æD NewSubscriberReply = RECORD canceled: Boolean; { O } container: EditionContainerSpec; { I/O } END; æC æKY SectionOptionsReply æFp Editions.p æT RECORD æD SectionOptionsReply = RECORD canceled: Boolean; { O } changed: Boolean; { O } sectionH: SectionHandle; { I } action: ResType; { O } END; æC æKY FormatIOParamBlock æFp Editions.p æT RECORD æD FormatIOParamBlock = RECORD ioRefNum: long; format: FormatType; formatIndex: long; offset: unsigned longint; buffPtr: Ptr; buffLen: unsigned longint; END; æC æKY EditionOpenerParamBlock æFp Editions.p æT RECORD æD EditionOpenerParamBlock = RECORD info: EditionInfoRecord; sectionH: SectionHandle; document: CanonicalFileSpecPtr; fdCreator: OSType; ioRefNum: long; ioProc: FormatIOProcPtr; success: Boolean; END; æC æKY InitEditionPack æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION InitEditionPack: OSErr; INLINE $3F3C,$0010,$303C,$0100,$A82D; æDT myVariable := InitEditionPack(paramList); æC You use the InitEditionPack function to initialize the Edition Manager. Before calling this funciton, be sure to determine if the Edition Manager is available on your system using the Gestalt function. FUNCTION InitEditionPack: OSErr; The InitEditionPack function returns an error if the pack could not be loaded or is an old version. If the InitEditionPack does not return noErr, there is not enough system heap to load the package. Result codes noErr 0 No error editionMgrInitErr -450 Could not load package MemError NewHandle errors ResError GetResource errors æKY NewSection æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION NewSection(container: EditionContinerSpecPtr;sectionDocument: CanonicalFileSpecPtr; kind: SectionType;sectionID: long;initalMode: UpdateMode;VAR sectionH: SectionHandle): OSErr; INLINE $303C,$0A02,$A82D; æDT myVariable := NewSection(container,sectionDocument,kind,sectionID,initalMode,sectionH); æC You use the NewSection routine to create a new section (either publisher or subscriber), and alias record from the sectionDocument (document that contains a section) to the edition container. The NewSection function allocates two handles; one handle for the section record and another handle for the alias record. FUNCTION NewSection (container: EditionContainerSpec; sectionDocument: CanonicalFileSpec; kind: SectionType; sectionID: LongInt; initialMode: UpdateMode; VAR sectionH: SectionHandle) : OSErr; The container parameter is the name of the file which holds the edition.The sectionDocument parameter is the file name (in canonical form) of the document that contains section. The sectionDocument parameter can be NIL if your current document has never been saved. If so, remember to call the AssociateSection function when the user finally saves the document to update the alias record of a registered section. The kind parameter designates the type of section (publisher or subscriber) being created. Identify the section with a unique number in the sectionID parameter. The initialMode parameter contains the update mode for the section. For publishers, this is either the constant pumOnSave or pumSuspend and for subscribers this is either sumAutomatic or sumOnRequestOnly. If the NewSection function fails, the sectionH parameter is set to NIL. If the function is successful, sectionH contains the handle to the allocated section record. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed badSubPartErr -454 Bad container spec badSectionErr -451 Not valid SectionType multiplePublisherWrn -460 Already is a publisher MemError NewHandle errors ??? NewAlias errors The NewSection function internally calls the RegisterSection function to inform the Edition Manager about a section. æKY RegisterSection æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION RegisterSection(sectionDocument: CanonicalFileSpec;sectionH: SectionHandle; VAR aliasWasChanged: Boolean): OSErr; INLINE $303C,$0604,$A82D; æDT myVariable := RegisterSection(sectionDocument,sectionH,aliasWasChanged); æC FUNCTION RegisterSection (sectionDocument: CanonicalFileSpec; sectionH: SectionHandle; VAR aliasWasChanged: Boolean;) : OSErr; The sectionDocument parameter is the file name of the document containing the section. This parameter cannot be NIL. The aliasWasChanged parameter returns TRUE if the alias for the edition container subscribed to is out of date. If so, the RegisterSection function updates the alias. This may occur if the file is moved to a new location or is renamed. The RegisterSection function adds the section record to the Edition Manager’s list of registered sections, and allocates a control block. After calling the RegisterSection function, the control block is either NIL or a valid control block. The control block is NIL if the RegisterSection function cannot locate the edition container being subscribed to. The RegisterSection function returns containerNotFoundWrn. You can compare control blocks for individual sections. If two sections contain the same control block value, these sections subscribe to the same edition. The Edition Manager needs to be informed when no sections are referencing a control block so that it can be deallocated. The control block maintains a count of how many sections are referencing it. Each time you use the UnRegisterSection function, the control block removes one from the number of sections. When the number of sections reaches 0, the control block is deallocated. For each section that you cannot register, you should display the document on the user’s screen, scroll to the location of the section, and then call the FindEditionContainerDialog function. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed badSectionErr -451 Not valid SectionType multiplePublisherWrn -460 Already is a publisher containerNotFoundWrn -461 Alias was not resolved ??? MatchAlias errors æKY UnRegisterSection æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION UnRegisterSection(sectionH: SectionHandle): OSErr; INLINE $303C,$0206,$A82D; æDT myVariable := UnRegisterSection(sectionH); æC When a section needs to be disposed of because the document containing the section is closing, or the user is canceling the section, you need to call the UnRegisterSection function. The sectionH parameter is a handle to the section record for a given section. The UnRegisterSection function removes the section from the application’s list of registered sections. You can then dispose of the section record and alias record with standard memory and resource manager calls. Once unregistered, a section does not received any events and cannot read or write any data. Depending on your clipboard strategy, you may want to unregister sections that have been cut into the clipboard. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed fBsyErr Section doing I/O notRegisteredSectionErr -452 Not registered æKY IsRegisterSection æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION IsRegisterSection(sectionH: SectionHandle): OSErr; INLINE $303C,$0208,$A82D; æDT myVariable := IsRegisterSection(sectionH); æC Each time your application receives a section event, your application must use the IsRegisteredSection function to verify that the event received is for a registered section. FUNCTION IsRegisteredSection (sectionH: SectionHandle) : OSErr; The sectionH parameter is a handle to the section record for a given section. The IsRegisteredSection function does not return a Boolean—noErr indicates that a section is registered. Result codes noErr 0 No error notRegisteredSectionErr -452 Not registered æKY FindEditionContainerDialog æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION FindEditionContainerDialog(sectionDocument: CanonicalFileSpec; sectionH: SectionHandle;VAR aliasWasChanged: Boolean): OSErr; INLINE $303C,$060A,$A82D; æDT myVariable := FindEditionContainerDialog(sectionDocument,sectionH,aliasWasChanged); æC If an edition container cannot be found for a particular section during registration, use the FindEditionContainerDialog to resolve the alias record of the section. FUNCTION FindEditionContainerDialog (sectionDocument: CanonicalFileSpec; SectionH: SectionHandle; VAR aliasWasChanged: Boolean) : OSErr; The sectionDocument parameter is the file name of the document containing a section in canonical form. This parameter cannot be NIL. If the FindEditionContainerDialog function is successful, the sectionH parameter contains the handle to the allocated section record. The aliasWasChanged parameter returns TRUE if the alias for the edition container that you are subscribing is out of date. This may occur if the file is moved to a new location or is renamed. The FindEditionContainerDialog functions assumes that your sections are contained within the linked list of registered sections.If the FindEditionContainerDialog function cannot locate the edition container, it will display a dialog box on the user’s screen. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed containerNotFoundWrn -461 Alias was not resolved multiplePublisherWrn -460 Already is a publisher ??? SelectAlias errors æKY AssociateSection æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION AssociateSection(sectionH: SectionHandle;newSectionDocument: CanonicalFileSpecPtr): OSErr; INLINE $303C,$040C,$A82D; æDT myVariable := AssociateSection(sectionH,newSectionDocument); æC If a user renames a document that contains sections or pastes a portion of a document that contains a section into another document, use the AssociateSection to update the alias record. FUNCTION AssociateSection (sectionH: SectionHandle; newSectionDocument: CanonicalFileSpec) : OSErr; The sectionH parameter is a handle to the section record for a given section. The newSectionDocument contains the volume, folder and file name of the new document. The AssociateSection function calls the update alias on the alias record. Result codes noErr 0 No error ??? UpdateAlias errors æKY CreateEditionContainerFile æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION CreateEditionContainerFile(editionFile: CanonicalFileSpec;fdCreator: OSType; editionFileNameScript: INTEGER): OSErr; INLINE $303C,$050E,$A82D; æDT myVariable := CreateEditionContainerFile(editionFile,fdCreator,editionFileNameScript); æC Each time a user creates a new publisher section within a document to an edition that does not already exist, you use the CreateEditionContainerFile to create an empty edition container. FUNCTION CreateEditionContainerFile (containerFile: CanonicalFileSpec; fdCreator: OSType) : OSErr; The containerFile parameter contains the volume, folder and file name for the edition container being created. The fdCreator parameter contains the creator type for the edition. The CreateEditionContainerFile function creates an empty edition container file (it does not contain any formats). This function creates a file with type 'publ'. If your application has a bundle, you should designate an icon for it now. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed ??? PBHCreate errors ??? PBHOpen errors ??? PBWrite errors æKY DeleteEditionContainerFile æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION DeleteEditionContainerFile(editionFile: CanonicalFileSpec): OSErr; INLINE $303C,$0210,$A82D; æDT myVariable := DeleteEditionContainerFile(editionFile); æC If a user cancels a publisher section within a document or closes a document containing a newly created publisher without saving, you need to remove the edition container using the DeleteEditionContainerFile function. FUNCTION DeleteEditionContainerFile (containerFile: CanonicalFileSpec) : OSErr; The containerFile parameter contains the volume, folder and file name for the edition container being deleted. You should use the DeleteEditionContainerFile function even if there are subscribers to the edition. When a subscriber section tries to read in data, it receives an error. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed ??? PBHDelete errors æKY OpenEdition æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION OpenEdition(subscriberSectionH: SectionHandle;VAR refNum: Byte): OSErr; INLINE $303C,$0412,$A82D; æDT myVariable := OpenEdition(subscriberSectionH,refNum); æC You initiate the reading of data from an edition (for a subscriber), use the OpenEdition function. FUNCTION OpenEdition (subscriberSectionH: SectionHandle; VAR refNum: EditionRefNum) : OSErr; The subscriberSectionH parameter is a handle to the section record for a given section. The refnum parameter returns the reference number for the edition. Multiple subscribers can simultaneously read data from a single edition. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed permErr Not a subscriber æKY OpenNewEdition æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION OpenNewEdition(publisherSectionH: SectionHandle;fdCreator: OSType; publisherSectionDocument: CanonicalFileSpecPtr;VAR refNum: EditionRefNum): OSErr; INLINE $303C,$0814,$A82D; æDT myVariable := OpenNewEdition(publisherSectionH,fdCreator,publisherSectionDocument,refNum); æC To initiate the writing of data from a publisher to its edition container, use the OpenNewEdition function. FUNCTION OpenNewEdition (publisherSectionH: SectionHandle; fdCreator: OSType; sectionDocument: CanonicalFileSpec; VAR refNum: EditionRefNum) : OSErr; The publisherSectionH parameter is the publisher section that you are writing to the edition. The fdCreator parameter is the Finder creator type of the new edition icon. The sectionDocument parameter is the document which contains the publisher. This parameter is used to create an alias from the edition to the document containing the publisher. If you pass NIL for sectionDocument, an alias is not made and the GotoPublisherSection function is unable to open the document containing the publisher. The refnum parameter returns the reference number for the edition. This parameter is necessary for subsequent calls to WriteEdition, SetEditionFormatMark, and CloseEdition to specify which publisher is writing its data to an edition. If the edition cannot be opened for writing because there is another publisher writing to it, or because the file system does not allow writing, an error is returned and refNum is set to NIL. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed wrPermErr Not a publisher notThePublisherWrn -462 Not the publisher ??? NewHandle errors ??? PBHCreate errors ??? PBHOpen errors ??? NewAlias errors æKY CloseEdition æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION CloseEdition(whichEdition: EditionRefNum;success: BOOLEAN): OSErr; INLINE $303C,$0316,$A82D; æDT myVariable := CloseEdition(whichEdition,success); æC After finishing reading from or writing to an edition, use the CloseEdition function to close the edition. FUNCTION CloseEdition (refNum: EditionRefNum; success: Boolean) : OSErr; The refnum parameter is the reference number for edition. Set the success parameter is set to TRUE if the edition successfully closes. If not, set this parameter to FALSE. When you are finished reading data from an edition and you are using the CloseEdition function, the EditionRefNum value becomes invalid. If the success parameter is set to TRUE, the CloseEdition function takes the modification date of the edition file that you have read in and puts it in the mdDate field of the subscriber’s section record. This indicates that the data contained in the edition and the subscriber section within the document are the same. If you set the success parameter to FALSE because you are unable to read the edition data (if there is not enough memory, or you didn’t find a format that you can read), the CloseEdition function closes the edition, but does not set the modification date field. This implies that the subscriber is not updated with the latest edition. When you have successfully finished writing data to an edition and you are using the CloseEdition function, you should set the success parameter to TRUE. When you do so, the data that you have written to the edition becomes available to any subscribers. The Edition Manager sends a SectionReadEvent to all current subscribers. The CloseEdition function sets the modification date (mdDate) of the edition to correspond to the modification date of the publisher’s section record. Each time a user edits a publisher within a document, you need to update the modification date (even if the data is not yet written). If you set the success parameter to FALSE because you are unable to successfully write data to the edition, the Edition Manager does not write any data to the edition. The data contained in the edition prior to writing is restored. SectionReadEvents are not sent to subscribers. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed rfNumErr Bad refNum ??? PBWrite errors ??? DisposHandle errors æKY EditionHasFormat æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION EditionHasFormat(whichEdition: EditionRefNum;whichFormat: FormatType; VAR length: Size): OSErr; INLINE $303C,$0618,$A82D; æDT myVariable := EditionHasFormat(whichEdition,whichFormat,length); æC Use the EditionHasFormat function to find out in which formats the edition data is available. FUNCTION EditionHasFormat (whichEdition: EditionRefNum; whichFormat: FormatType; VAR length: Size) : OSErr; The whichEdition parameter is the reference number for the edition. The whichFormat parameter indicates the format type that you are requesting. Apple Computer recommends that you request formats in order of preference. Upon return of the EditionHasFormat function, the length parameter contains the length of the format for the edition you are specifying. If the requested format is available, this function returns noErr and the length field returns the size of the data in the specified format or kFormatLengthUnknown (-1) which signifies that the size is unknown. You should continue to read the format until there is no more data. Be aware that the EditionHasFormat function may return kFormatLengthUnknown for the length of the format. Result codes noErr 0 No error noTypeErr Format not available editionMgrInitErr -450 Manager not init’ed æKY ReadEdition æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION ReadEdition(whichEdition: EditionRefNum;whichFormat: FormatType; buffPtr: Ptr;VAR buffLen: Size): OSErr; INLINE $303C,$081A,$A82D; æDT myVariable := ReadEdition(whichEdition,whichFormat,buffPtr,buffLen); æC Use the ReadEdition function to read data from an edition. FUNCTION ReadEdition (whichEdition: EditionRefNum; whichFormat: FormatType; buffPtr: Ptr; VAR buffLen: Size) : OSErr; The whichEdition parameter is the reference number for the edition. The whichFormat parameter indicates the format type that you want to read. The buffPtr parameter is a pointer to the buffer into which you are reading the edition from. The buffLen parameter is the number of bytes that you want to read into the buffer. The buffLen parameter is also a return value that returns the total number of bytes read into the buffer. Once the buffLen field returns a value less than the value you have specified, there is no additional data to read, and the ReadEdition function returns noErr. If use the ReadEdition function after all data is read in, the ReadEdition function returns an EoFErr. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed noTypeErr Format not available rfNumErr Bad refNum EofErr æKY WriteEdition æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION WriteEdition(whichEdition: EditionRefNum;whichFormat: FormatType; buffPtr: Ptr;buffLen: Size): OSErr; INLINE $303C,$081C,$A82D; æDT myVariable := WriteEdition(whichEdition,whichFormat,buffPtr,buffLen); æC Use the WriteEdition function to write data to an edition. FUNCTION WriteEdition (refNum: EditionRefNum; whichFormat: FormatType; buffPtr: Ptr; buffLen: Size) : OSErr; The refnum parameter is the reference number for edition. The whichFormat parameter indicates the format type that you want to write. The buffPtr parameter is a pointer to the buffer that you are writing into the edition. The buffLen parameter is the number of bytes that you are writing. If data cannot be entirely written to the edition, the WriteEdition function returns a error. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed noTypeErr Unknown format rfNumErr Bad refNum æKY GetEditionFormatMark æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION GetEditionFormatMark(whichEdition: EditionRefNum;whichFormat: FormatType; VAR currentMark: LONGINT): OSErr; INLINE $303C,$061E,$A82D; æDT myVariable := GetEditionFormatMark(whichEdition,whichFormat,currentMark); æC Use the GetEditionFormatMark to locate the current marker for a particular format. FUNCTION GetEditionFormatMark (whichEdition: EditionRefNum; whichFormat: FormatType; VAR currentMark: LongInt) : OSErr; The whichEdition parameter is the reference number for the edition. The whichFormat parameter indicates the format type for the edition and the currentMark parameter is the offset for the format. If you do not support the format that you are specifying, you receive noTypeErr. Result codes noErr 0 No error noTypeErr Unknown format posErr Mark not set anywhere æKY SetEditionFormatMark æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION SetEditionFormatMark(whichEdition: EditionRefNum;whichFormat: FormatType; setMarkTo: LONGINT): OSErr; INLINE $303C,$0620,$A82D; æDT myVariable := SetEditionFormatMark(whichEdition,whichFormat,setMarkTo); æC Use the SetEditionFormatMark to set the current mark for a section format. FUNCTION SetEditionFormatMark (whichEdition: EditionRefNum; whichFormat: FormatType; setMarkTo: LongInt) : OSErr; The whichEdition parameter is the reference number for the edition. The whichFormat parameter indicates the format type for the edition and the setMarkTo parameter is the offset for the format. When you are creating a publisher, and if the whichFormat does not exist for a particular edition that you are writing data to, the SetEditionFormatMark creates the format. You need to call the SetEditionFormatMark function before writing data. Result codes noErr 0 No error posErr Manager not init’ed ??? SetHandleSize errors æKY GetEditionInfo æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION GetEditionInfo(sectionH: SectionHandle;VAR editionInfo: EditionInfoRecord): OSErr; INLINE $303C,$0422,$A82D; æDT myVariable := GetEditionInfo(sectionH,editionInfo); æC When the user wants to locate the publisher for a particular subscriber (by choosing Find Publisher in the subscriber options dialog box), use the GetEditionInfo function to find the edition container. You should then call the GotoPublisherSection function. The GetEditionInfo function returns information about a section’s edition such as it’s location, last modification date, creator and type. This function only works for registered sections which contain a non-NIL control block. FUNCTION GetEditionInfo (sectionH: SectionHandle; VAR editionInfo: EditionInfoRecord) : OSErr; The sectionH parameter is a handle to the section record for a given section. The editionInfo parameter is a pointer from the EditionInfo record. The GetEditionInfo function comprises the public information contained in the control block. The Edition Manager syncs to ensure that the existing edition name corresponds to the Finder’s existing edition name. Refer to “Reading and Writing Edition Data” for additional information. If an edition container could not be located previously, the GetEditionInfo function tries to locate it again. If it cannot be located a second time, the GetEditionInfo function returns a file not found err. TYPE EditionInfoRecord = RECORD crDate: TimeStamp; mdDate: TimeStamp; fdCreator: OSType; fdType: OSType; container: EditionContainerSpec; END; The fdType field is the creator type 'publ'. The fdCreator field is specified in the OpenNewEdition function. The container field is a volume, folder, and file name for the edition. The crDate field contains the creation date of the edition. The mdDate field contains the modification date of the edition. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed fnfErr Not registered or file moved ??? PBHGetFInfo Use the GetEditionFormatMark to locate the current marker for a particular format. FUNCTION GetEditionFormatMark (whichEdition: EditionRefNum; whichFormat: FormatType; VAR currentMark: LongInt) : OSErr; The whichEdition parameter is the reference number for the edition. The whichFormat parameter indicates the format type for the edition and the currentMark parameter is the offset for the format. If you do not support the format that you are specifying, you receive noTypeErr. Result codes noErr 0 No error noTypeErr Unknown format posErr Mark not set anywhere æKY GotoPublisherSection æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION GotoPublisherSection(VAR container: EditionContainerSpec): OSErr; INLINE $303C,$0224,$A82D; æDT myVariable := GotoPublisherSection(container); æC Use the GotoPublisherSection function to resolve the alias in the edition to find the document containing its publisher. This function opens the document, launches it’s application if necessary, and scrolls to the location of the publisher. FUNCTION GotoPublisherSection (container: EditionContainerSpec) : OSErr; The container parameter is the edition volume, folder, and file name. You obtain the container by calling the GetEditionInfo function. You should call the GotoPublisherSection function when the user selects Find Publisher within the publisher options dialog box. The action code 'goto' is returned to you. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed badSubPartErr -454 Invalid container MemError NewHandle errors ??? ResolveAlias errors æKY GetLastEditionContainerUsed æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION GetLastEditionContainerUsed(VAR container: EditionContainerSpec): OSErr; INLINE $303C,$0226,$A82D; æDT myVariable := GetLastEditionContainerUsed(container); æC Use the GetLastEditionContainerUsed function to display the last edition within the dialog boxes. This function enables a user to easily subscribe to the data recently published. FUNCTION GetLastEditionContainerUsed (VAR container: EditionContainerSpec) : OSErr; If the GetLastEditionContainer function locates the last edition for which a section was created, the container parameter contains its volume, folder, file name, part, and returns noErr. (The last edition created is associated with the last time that you used the NewSection function.) If the last edition created to is moved or deleted, the GetLastEditionContainer function cannot locate the last edition. The container parameter returns the volume and folder for the edition, leaves the file name blank, and returns fnfErr. The Edition Manager syncs to ensure that its existing edition name corresponds to the Finder’s existing edition name. Refer to “Reading and Writing Edition Data” for additional information. Pass the information from the GetLastEditionContainerUsed function to the NewSubscriberDialog and the NewPublisherDialog functions. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed fnfErr Container not found æKY GetStandardFormats æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION GetStandardFormats(container: EditionContainerSpec;VAR previewFormat: FormatType; preview: Handle;publisherAliss: Handle;formats: Handle): OSErr; INLINE $303C,$0A28,$A82D; æDT myVariable := GetStandardFormats(container,previewFormat,preview,publisherAliss,formats); æC This function is called by the Edition Manager to get the alias used in the GotoPublisherSection function and to get the preview shown in the new subscriber dialog box. You will probably not need to call this function directly. FUNCTION GetStandardFormats (container: EditionContainerSpec; VAR previewFormat: FormatType; preview: publisherAlias; formats: Handle) : OSErr; The container parameter is a pointer to the edition volume, folder, file name and part. You should pass in valid handes for the formats that you want and NIL for the formats that you don’t want. The handles are resized to the size of the data. The handle fmts reads the virtual format kFormatListFormat, the handle alis reads the format kPublisherDocAliasFormat and the handle prvw tries to find the following formats in this order: prvw, PICT and then TEXT. The first format located returns in the preview handle and the previewFormat parameter is set to its type. If none of the requested formats can be found, noTypeErr is returned. Result codes noErr 0 No error editionMgrInitErr -450 Manager not init’ed noTypeErr Container not found MemError SetHandleSize errors ??? ResolveAlias errors æKY GetEditionOpenerProc æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION GetEditionOpenerProc(VAR opener: EditionOpenerProcPtr): OSErr; INLINE $303C,$022A,$A82D; æDT myVariable := GetEditionOpenerProc(opener); æC Use the GetEditionOpenerProc to locate the current edition opener procedure. FUNCTION GetEditionOpenerProc (VAR opener: EditionOpenerProcPtr) : OSErr; The opener procedure returns the pointer to the current edition opener procedure. æKY SetEditionOpenerProc æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION SetEditionOpenerProc(opener: EditionOpenerProcPtr): OSErr; INLINE $303C,$022C,$A82D; æDT myVariable := SetEditionOpenerProc(opener); æC Use the SetEditionOpenProc to provide your own edition opener procedure. FUNCTION SetEditionOpenerProc (opener: EditionOpenerProcPtr) : OSErr; The opener parameter is a pointer to the edition opener procedure that you are providing. æKY CallEditionOpenerProc æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION CallEditionOpenerProc(selector: EditionOpenerVerb;VAR PB: EditionOpenerParamBlock; routine: EditionOpenerProcPtr): OSErr; INLINE $303C,$052E,$A82D; æDT myVariable := CallEditionOpenerProc(selector,PB,routine); æC The Edition Manager never opens or closes an edition container directly—it calls the current “EditionOpener.” Use the CallEditionOpenerProc to call the edition opener procedure pointer. FUNCTION CallEditionOpenerProc (selector: EditionOpenerVerb; VAR params: EditionOpenerParamBlock; routine: EditionOpenerProcPtr) : OSErr; Set the selector parameter to one of the edition opener verbs (eoOpen, eoClose, eoOpenNew, eoCloseNew, eoCanSubscribe). The params parameter is an EditionOpenerParamBlock record. TYPE EditionOpenerParamBlock = RECORD info: EditionInfoRecord; {} sectionH: SectionHandle; {} document: CanonicalFileSpecPtr; {} misc: LongInt; {} ioRefNum: LongInt; {} ioProc: FormatIOProcPtr; {} END; The routine parameter is a pointer to an edition opener procedure. æKY CallFormatIOProc æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION CallFormatIOProc(selector: FormatIOVerb;VAR PB: FormatIOParamBlock; routine: FormatIOProcPtr): OSErr; INLINE $303C,$0530,$A82D; æDT myVariable := CallFormatIOProc(selector,PB,routine); æC The PB parameter of the CallFormatIOProc function is a FormatIOParamBlock record. TYPE FormatIOParamBlock = RECORD ioRefNum: LongInt; {} format: FormatType; {} formatIndex: LongInt; {} offset: LongInt; {} buffPtr: Ptr; {} buffLen: LongInt; {} END; The routine parameter is a pointer to a format I/O procedure. You should have an IO function that contains the following parameters. FUNCTION IO (selector: FormatIOVerb; VAR PB: FormatIOParamBlock) : OSErr; æKY NewSubscriberDialog æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION NewSubscriberDialog(VAR reply: NewSubscriberReply): OSErr; INLINE $303C,$0232,$A82D; æDT myVariable := NewSubscriberDialog(reply); æC Use the NewSubscriberDialog function to display the new subscriber dialog box on the user’s screen. FUNCTION NewSubscriberDialog (VAR reply: NewSubscriberReply) : OSErr; The reply parameter is the NewSubscriberReply record. TYPE NewSubscriberReply = RECORD canceled: Boolean; {out} container: EditionContainerSpec; {in/out} END; Set the container parameter to be a pointer to a volume, folder, file name, and part for the last edition subscribed to. Upon return of the NewSubscriberDialog function, if the canceled parameter is set to TRUE, the user canceled the dialog box. Otherwise, this parameter is FALSE and the container parameter holds the container for the new subscriber. Result codes noErr 0 No error editionMgrInitErr -450 Package not init’ed badSubPartErr -454 Bad container spec MemError NewHandle errors ResError GetResource errors æKY NewSubscriberExpDialog æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION NewSubscriberExpDialog(VAR reply: NewSubscriberReply;where: Point; expansionDITLresID: INTEGER;dlgHook: ExpDlgHookProcPtr;filterProc: ExpModalFilterProcPtr; yourDataPtr: Ptr): OSErr; INLINE $303C,$0B34,$A82D; æDT myVariable := NewSubscriberExpDialog(reply,where,expansionDITLresID,dlgHook,filterProc,yourDataPtr); æC Use the NewSubscriberExpDialog function to customize the new subscriber dialog box. FUNCTION NewSubscriberExpDialog (VAR reply: NewSubscriberReply; where: Point; expansionDITLresID: Integer; dlgHook: ExpDlgHookProcPtr; filterProc: ExpModalFilterProcPtr; callBackPtr: Ptr) : OSErr; The NewSubscriberExpDialog, NewPublisherExpDialog, and SectionOptionsExpDialog functions share the same parameters. Refer below for a detailed explanation of the parameters. Result codes noErr 0 No error editionMgrInitErr -450 Package not init’ed MemError NewHandle errors ResError GetResource errors æKY NewPublisherDialog æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION NewPublisherDialog(VAR reply: NewSubscriberReply): OSErr; INLINE $303C,$0236,$A82D; æDT myVariable := NewPublisherDialog(reply); æC Use the NewPublisherDialog function to display the new publisher dialog box on the user’s screen. FUNCTION NewPublisherDialog (VAR reply: NewPublisherReply) : OSErr; The reply parameter is a pointer from the NewPublisherReply record. TYPE NewPublisherReply = RECORD canceled: Boolean; {out} replacing: Boolean; {out} usePart: Boolean; {in} preview: Handle; {in} previewFormat: FormatType; {in} container: EditionContainerSpec {in/out} END; The usePart parameter must be set to FALSE before calling the NewPublisherDialog routine. Set the container parameter to be a pointer to a volume, folder, and file name for a default edition. Set the preview parameter to be a handle to the format for the default edition and set the previewFormat parameter to indicate the format of the default edition. Upon return of the NewPublisherDialog function, the following three output parameters can be set. If the canceled parameter is set to TRUE, the user canceled the dialog box. If the replacing parameter is TRUE, the user chose an existing file name from the list of available editions and confirmed this replacement. If the replacing parameter is TRUE, do not call the CreateEditionContainerFile function which creates a new edition container. The container parameter contains the volume, folder and file name for the default edition. Deallocate the preview parameter to free up memory. Result codes noErr 0 No error editionMgrInitErr -450 Package not init’ed badSubPartErr -454 Bad container spec MemError NewHandle errors ResError GetResource errors æKY NewPublisherExpDialog æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION NewPublisherExpDialog(VAR reply: NewSubscriberReply;where: Point; expansionDITLresID: INTEGER;dlgHook: ExpDlgHookProcPtr;filterProc: ExpModalFilterProcPtr; yourDataPtr: UNIV Ptr): OSErr; INLINE $303C,$0B38,$A82D; æDT myVariable := NewPublisherExpDialog(reply,where,expansionDITLresID,dlgHook,filterProc,yourDataPtr); æC Use the NewPublisherExpDialog function to customize the new publisher dialog box. FUNCTION NewPublisherExpDialog (VAR reply: NewPublisherReply; where: Point; expansionDITLresID: Integer; dlgHook: ExpDlgHookProcPtr; filterProc: ExpModalFilterProcPtr; callBackPtr: Ptr) : OSErr; The NewSubscriberExpDialog, NewPublisherExpDialog, and SectionOptionsExpDialog functions share the same parameters. Refer below for a detailed explanation of the parameters. Result codes noErr 0 No error editionMgrInitErr -450 Package not init’ed MemError NewHandle errors ResError GetResource errors æKY SectionOptionsDialog æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION SectionOptionsDialog(VAR reply: SectionOptionsReply): OSErr; INLINE $303C,$023A,$A82D; æDT myVariable := SectionOptionsDialog(reply); æC Use the SectionOptionsDialog function to display the publisher options and subscriber options dialog boxes on the user’s screen. FUNCTION SectionOptionsDialog (VAR reply: SectionOptionsReply) : OSErr; The reply parameter is a pointer from the SectionOptionsReply record. TYPE SectionOptionsReply = RECORD canceled: Boolean; {out} changed: Boolean; {out} sectionH: SectionHandle; {in} action: ResType; {out} END; The sectionH parameter is a handle to the section record for a given section. Upon return of the SectionOptionsDialog function, the following output parameters can be set. If the canceled parameter is set to TRUE, the user canceled the dialog box. Otherwise, this parameter is FALSE. If the changed parameter is TRUE (if for example, the update mode is changed), the user changed the section record. The action parameter contains the code for 1 of 4 user actions. • action code is 'read' for user selection of Get Edition Now • action code is 'writ' for user selection of Publish Now • action code is 'goto' for user selection of Find Publisher • action code is 'cncl' for user selection of Cancel Publisher or Cancel Subscriber Your application can expand dialog boxes to include DITL items, apply alternate mapping of events to item hits, and apply alternate meanings to the item hits. æKY SectionOptionsExpDialog æFp Editions.p æT FUNCTION æTN A82D æD FUNCTION SectionOptionsExpDialog(VAR reply: SectionOptionsReply;where: Point; expansionDITLresID: INTEGER;dlgHook: ExpDlgHookProcPtr;filterProc: ExpModalFilterProcPtr; yourDataPtr: UNIV Ptr): OSErr; INLINE $303C,$0B3C,$A82D; æDT myVariable := SectionOptionsExpDialog(reply,where,expansionDITLresID,dlgHook,filterProc,yourDataPtr); æC Use the SectionOptionsExpDialog function to customize the publisher and subscriber dialog boxes. FUNCTION SectionOptionsExpDialog (VAR reply: SectionOptionsReply; where: Point; expansionDITLresID: Integer; dlgHook: ExpDlgHookProcPtr; filterProc: ExpModalFilterProcPtr; callBackPtr: Ptr) : OSErr; æKY EPPC.p æKL AcceptHighLevelEvent GetPortNameFromProcessSerialNumber GetProcessSerialNumberFromPortName GetSpecificHighLevelEvent PostHighLevelEvent bufferIsSmall connectionInValid HighLevelEventMsg HighLevelEventMsgClass HighLevelEventMsgHdl HighLevelEventMsgPtr kHighLevelEvent msgWasFullyAccepted msgWasNotAccepted msgWasPartiallyAccepted nAttnMsg noOutstandingHLE nReturnReceipt priorityMask receiverIDisPSN receiverIDisSessionID receiverIDisSignature receiverIDisTargetID receiverIDMask registerOnNetwork rtrnReciptMsgID systemOptionsMask TargetID TargetIDPtr æKY kHighLevelEvent æFp EPPC.p æT CONST æD kHighLevelEvent = 23; æC æKY receiverIDMask æFp EPPC.p æT CONST æD { postOptions currently supported } receiverIDMask = $0000F000; æC æKY receiverIDisPSN æFp EPPC.p æT CONST æD receiverIDisPSN = $00008000; æC æKY receiverIDisSignature æFp EPPC.p æT CONST æD receiverIDisSignature = $00007000; æC æKY receiverIDisSessionID æFp EPPC.p æT CONST æD receiverIDisSessionID = $00006000; æC æKY receiverIDisTargetID æFp EPPC.p æT CONST æD receiverIDisTargetID = $00005000; æC æKY systemOptionsMask æFp EPPC.p æT CONST æD systemOptionsMask = $00000F00; æC æKY nReturnReceipt æFp EPPC.p æT CONST æD nReturnReceipt = $00000200; æC æKY priorityMask æFp EPPC.p æT CONST æD priorityMask = $000000FF; æC æKY nAttnMsg æFp EPPC.p æT CONST æD nAttnMsg = $00000001; æC æKY registerOnNetwork æFp EPPC.p æT CONST æD registerOnNetwork = $80000000; æC æKY bufferIsSmall æFp EPPC.p æT CONST æD { error returns from Post and Accept */ } bufferIsSmall = -607; æC æKY noOutstandingHLE æFp EPPC.p æT CONST æD noOutstandingHLE = -608; æC æKY connectionInValid æFp EPPC.p æT CONST æD connectionInValid = -609; æC æKY HighLevelEventMsgClass æFp EPPC.p æT CONST æD { constant for return receipts */ } HighLevelEventMsgClass = 'jaym'; æC æKY rtrnReciptMsgID æFp EPPC.p æT CONST æD rtrnReciptMsgID = 'rtrn'; æC æKY msgWasPartiallyAccepted æFp EPPC.p æT CONST æD msgWasPartiallyAccepted = 2; æC æKY msgWasFullyAccepted æFp EPPC.p æT CONST æD msgWasFullyAccepted = 1; æC æKY msgWasNotAccepted æFp EPPC.p æT CONST æD msgWasNotAccepted = 0; æC æKY TargetID TargetIDPtr æFp EPPC.p æT RECORD æD TargetIDPtr = ^TargetID; TargetID = RECORD sessionID: long; name: PortName; location: LocName; recvrName: PortName; END; æC æKY HighLevelEventMsg HighLevelEventMsgPtr HighLevelEventMsgHdl æFp EPPC.p æT RECORD æD HighLevelEventMsgPtr = ^HighLevelEventMsg; HighLevelEventMsgHdl = ^HighLevelEventMsgPtr; HighLevelEventMsg = RECORD sessionID: long; HighLevelEventMsgHeaderLength: unsigned word; version: unsigned word; reserved1: unsigned longint; theMsgEvent: EventRecord; userRefcon: unsigned longint; postingOptions: unsigned longint; msgLength: unsigned longint; END; æC æKY PostHighLevelEvent æFp EPPC.p æT FUNCTION æTN A88F æD FUNCTION PostHighLevelEvent(theEvent: EventRecord;receiverID: Ptr;msgRefcon: unsigned longint; msgBuff: Ptr;msgLen: unsigned longint;postingOptions: unsigned longint): OSErr; INLINE $3F3C,$0034,$A88F; æDT myVariable := PostHighLevelEvent(theEvent,receiverID,msgRefcon,msgBuff,msgLen,postingOptions); æC You can use the PostHighLevelEvent routine to send a high-level event to another application. FUNCTION PostHighLevelEvent (theEvent: EventRecord; receiverID: Ptr {UNIV LongInt}; msgRefcon: LongInt; msgBuff: Ptr; msgLen: LongInt; postingOptions: LongInt) : OSErr; You specify the event to send in parameter theEvent, and include any additional data for the event by providing a pointer to a data buffer in the msgBuff parameter. The msgLen parameter specifies the size of the data buffer. The receiverID parameter specifies the recipient of the event. The msgRefcon parameter specifies a unique number associated with this event. Your application can set this field to any value it chooses. You can specify the receiver of the event by session ID, process serial number, signature, or port name and port location. You can use any of these specifications to send an event to another application on the local machine. You can use only the session ID or port name and port location to send an event to an application on a remote machine. You use the postingOptions parameter to specify delivery options and options associated with the receiverID parameter. You can specify one or more delivery options to indicate whether you want the other application to receive the event at the next opportunity, and to indicate whether you want acknowledgment that the event was received by the other application. You use the options associated with the receiverID parameter to indicate how you are specifying the recipient of the event. Result codes noErr 0 Mo error connectionInValid –609 Connection is invalid æKY AcceptHighLevelEvent æFp EPPC.p æT FUNCTION æTN A88F æD FUNCTION AcceptHighLevelEvent(VAR sender: TargetID;VAR msgRefcon: LONGINT; msgBuff: Ptr;VAR msgLen: LONGINT): OSErr; INLINE $3F3C,$0033,$A88F; æDT myVariable := AcceptHighLevelEvent(sender,msgRefcon,msgBuff,msgLen); æC Some high-level events may be fully specified by their event record only, while others may include additional information in an optional buffer. To get any additional information and to find the sender of the event, use the AcceptHighLevelEvent function. FUNCTION AcceptHighLevelEvent (VAR sender: TargetID; VAR msgRefcon: LongInt; msgBuff: Ptr; VAR msgLen: LongInt) : OSErr; The sender of the event is specified in the sender parameter, which is a pointer to a TargetID data structure. The sender parameter contains the session reference number that identifes this communication and the port name and port location of the sender. The msgRefcon parameter is a unique number that is used to identify this event. If you send a response to this event, you should specify the same value of msgRefcon so that the sender of the event can associate the reply with the original request. The msgBuff parameter points to any additional data associated with the event. The msgLen parameter contains the size of the buffer. Your application is responsible for allocating the memory for the additional data pointed to by the msgBuff parameter. If the msgBuff parameter points to an area in memory that is not large enough to hold all the data associated with the event, AcceptHighLevelEvent returns the result code bufferIsSmall. If AcceptHighLevelEvent returns the result code bufferIsSmall, the msgLen parameter contains the number of bytes remaining. You can call AcceptHighLevelEvent again to receive the rest of the data. Result codes noErr 0 No error bufferIsSmall –607 Buffer is too small noOutstandingHLE –608 No outstanding high-level event æKY GetProcessSerialNumberFromPortName æFp EPPC.p æT FUNCTION æTN A88F æD FUNCTION GetProcessSerialNumberFromPortName(portName: PortNamePtr;VAR pPSN: ProcessSerialNumberPtr): OSErr; INLINE $3F3C,$0035,$A88F; æDT myVariable := GetProcessSerialNumberFromPortName(portName,pPSN); æC æKY GetPortNameFromProcessSerialNumber æFp EPPC.p æT FUNCTION æTN A88F æD FUNCTION GetPortNameFromProcessSerialNumber(VAR portName: PortNamePtr;pPSN: ProcessSerialNumberPtr): OSErr; INLINE $3F3C,$0046,$A88F; æDT myVariable := GetPortNameFromProcessSerialNumber(portName,pPSN); æC æKY GetSpecificHighLevelEvent æFp EPPC.p æT FUNCTION æTN A88F æD FUNCTION GetSpecificHighLevelEvent(aFilter: GetSpecificFilterProcPtr;VAR params: unsigned longint; VAR err: OSErr): Boolean; INLINE $3F3C,$0045,$A88F; æDT myVariable := GetSpecificHighLevelEvent(aFilter,params,err); æC You can use the GetSpecificHighLevelEvent function to select and optionally retrieve a specific high-level event from the high-level event queue. FUNCTION GetSpecificHighLevelEvent (aFilter:ProcPtr; VAR params: LongInt; VAR err: OSErr) : Boolean; You specify your filter function in the aFilter parameter. GetSpecificHighLevelEvent calls your filter function once for each event on the high-level event queue until your filter function returns TRUE or the end of the queue is reached. You use the params parameter to specify the criteria your filter function should use to select a specific event. For example, you can specify the params parameter as a msgRefcon value to search for a particular event or as a pointer to a targetID structure to search for a specific sender of an event. Or you can search for a specific class of event. Here’s how you declare the filter function aFilter: FUNCTION aFilter (VAR params: LongInt; msgBuff: HighLevelEventMsgPtr; sender: TargetID) : Boolean; The params parameter indicates the criteria your filter function should use to search for a specific event. The msgBuff parameter contains a pointer to a record of type HighLevelEventMsg, which provides information about the event: the event record for the high-level event, the posting options of the event, and so forth. The sender parameter contains the target ID of the application that sent the event. Your filter function can compare the contents of the params parameter with the contents of the msgBuff or senderID parameters. If your filter function finds a match, your filter function should return TRUE. If it does not find a match, your filter function should return FALSE. æKY ErrMgr.p æKL AddErrInsert CloseErrMgr GetSysErrText GetToolErrText InitErrMgr æKY AddErrInsert æFp ErrMgr.p æT PROCEDURE æD PROCEDURE AddErrInsert(insert: Str255;msgString: StringPtr); C; æDT AddErrInsert(insert,msgString); æC { Add another insert to an error message string.This call is used when more than one insert is to be added to a message (because it contains more than one '^' character). } æKY CloseErrMgr æFp ErrMgr.p æT PROCEDURE æD PROCEDURE CloseErrMgr; C; æDT CloseErrMgr; æC { Ideally a CloseErrMgr should be done at the end of execution to make sure all files opened by the ErrMgr are closed. You can let normal program termination do the closing. But if you are a purist... } æKY GetSysErrText æFp ErrMgr.p æT PROCEDURE æD PROCEDURE GetSysErrText(msgNbr: INTEGER;errMsg: StringPtr); æDT GetSysErrText(msgNbr,errMsg); æC (* Get the error message text corresponding to system error number errNbr from the system error message file (whose name was specified in the InitErrMgr call). The text of the message is returned in errMsg and the function returns a pointer to errMsg. The maximum length of the message is limited to 254 characters. Note, if a system message filename was not specified to InitErrMgr, then the ErrMgr assumes the message file contained in the file "SysErrs.Err". This file is first accessed as " {ShellDirectory}SysErrs.Err" on the assumption that SysErrs.Err is kept in the same directory as the MPW Shell. If the file cannot be opened, then an open is attempted on "SysErrs.Err" in the System Folder. *) æKY GetToolErrText æFp ErrMgr.p æT PROCEDURE æD PROCEDURE GetToolErrText(msgNbr: INTEGER;errInsert: Str255;errMsg: StringPtr); æDT GetToolErrText(msgNbr,errInsert,errMsg); æC (* Get the error message text corresponding to tool error number errNbr from the tool error message file (whose name was specified in the InitErrMgr call). The text of the message is returned in errMsg and the function returns a pointer to errMsg. The maximum length of the message is limited to 254 characters. If the message is to have an insert, then ErrInsert should be a pointer to it. Otherwise it should be either be a null string or a NULL pointer. Inserts are indicated in error messages by specifying a '^' to indicate where the insert is to be placed. Note, if a tool message filename was not specified to InitErrMgr, then the ErrMgr assumes the message file contained in the data fork of the tool calling the ErrMgr. This name is contained in the Shell variable {Command} and the value of that variable is used to open the error message file. *) æKY InitErrMgr æFp ErrMgr.p æT PROCEDURE æD PROCEDURE InitErrMgr(toolErrFilename: Str255;sysErrFilename: Str255; showToolErrNbrs: BOOLEAN); æDT InitErrMgr(toolErrFilename,sysErrFilename,showToolErrNbrs); æC { ErrMgr initialization.This must be done before using any other ErrMgr routine. Set showToolErrNbrs to true if you want all tool messages to contain the error number following the message text enclosed in parentheses (e.g., "<msg txt> ([OS] Error <n>)"; system error messages always contain the error number). The toolErrFileName parameter is used to specify the name of a tool-specific error file, and should be the NULL or a null string if not used (or if the tool's data fork is to be used as the error file, see GetToolErrText for futher details). The sysErrFileName parameter is used to specify the name of a system error file, and should normally be the NULL or a null string, which causes the ErrMgr to look in the MPW Shell directory for "SysErrs.Err" (see GetSysErrText). } æKY Errors.p æKL SysError abortErr addRefFailed addResFailed afpAccessDenied afpAuthContinue afpBadUAM afpBadVersNum afpBitmapErr afpCallNotSupported afpCantMove afpCantRename afpDenyConflict afpDirNotEmpty afpDirNotFound afpDiskFull afpEofError afpFileBusy afpFlatVol afpIconTypeError afpItemNotFound afpLockErr afpMiscErr afpNoMoreLocks afpNoServer afpObjectExists afpObjectLocked afpObjectNotFound afpObjectTypeErr afpParmErr afpRangeNotLocked afpRangeOverlap afpServerGoingDown afpSessClosed afpTooManyFilesOpen afpUserNotAuth afpVolLocked aspBadVersNum aspBufTooSmall aspNoAck aspNoMoreSess aspNoServers aspParamErr aspServerBusy aspSessClosed aspSizeErr aspTooMany atpBadRsp atpLenErr badATPSkt badBtSlpErr badBuffNum badChannel badCksmErr badDBtSlp badDCksum badEditionFileErr badFormat badMDBErr badMovErr badSectionErr badSubPartErr badUnitErr bdNamErr breakRecd buf2SmallErr cantStepErr catChangedErr cbNotFound cDevErr ckSumErr clkRdErr clkWrErr closErr cMatchErr cNoMemErr containerAlreadyOpenWrn containerNotFoundWrn controlErr corErr cProtectErr cRangeErr cResErr cTempMemErr dataVerErr dceExtErr ddpLenErr ddpSktErr DiffVolErr dInstErr dirFulErr dirNFErr dRemovErr dsAddressErr dsBadLaunch dsBadPatch dsBadSANEopcode dsBadSlotInt dsBusError dsChkErr dsCoreErr dsFinderErr dsFPErr dsFSErr dsGreeting dsHMenuFindErr dsIllInstErr dsIOCoreErr dsIrqErr dskFulErr dsLineAErr dsLineFErr dsLoadErr dsMBarNFnd dsMemFullErr dsMiscErr dsNoPackErr dsNoPatch dsNoPk1 dsNoPk2 dsNoPk3 dsNoPk4 dsNoPk5 dsNoPk6 dsNoPk7 dsNotThe1 dsOvflowErr dsPrivErr dsReinsert dsStknHeap dsSysErr dsTraceErr dsZeroDivErr dupFNErr editionMgrInitErr envBadVers envNotPresent envVersTooBig eofErr evtNotEnb excessCollsns extFSErr extractErr exUserBreak fBsyErr fidExists fidNotFound firstDskErr fLckdErr fmt1Err fmt2Err fnfErr fnOpnErr fontDecError fontNotDeclared fontSubErr framingErr fsDSIntErr fsRnErr gcrOnMFMErr gfpErr hMenuFindErr hwOverrunErr hwParamErr iIOAbortErr initIWMErr ioErr lapProtErr lastDskErr mapReadErr mBarNFnd memAdrErr memAZErr memBCErr memFullErr memLockedErr memPCErr memPurErr memROZErr memROZWarn memSCErr memWZErr menuPrgErr mFulErr multiplePublisherWrn nbpBuffOvr nbpConfDiff nbpDuplicate nbpNISErr nbpNoConfirm nbpNotFound negZcbFreeErr nilHandleErr nmTypErr noAdrMkErr noBridgeErr noDataArea noDriveErr noDtaMkErr noHardware noMacDskErr noMPPErr noNybErr noRelErr noScrapErr noSendResp NotAFileErr notEnoughHardware notOpenErr notRegisteredSectionErr notThePublisherWrn noTypeErr nsDrvErr nsvErr offLinErr openErr opWrErr paramErr parityErr permErr pixMapTooDeepErr portInUse portNotCf posErr prInitErr prWrErr qErr queueFull rcvrErr readErr readQErr recNotFnd reqAborted reqFailed resAttrErr resFNotFound resNotFound resProblem rfNumErr rgnTooBigErr rmvRefFailed rmvResFailed sdmInitErr sdmJTInitErr sdmPRAMInitErr sdmPriInitErr sdmSRTInitErr sectNFErr seekErr seNoDB shutDownAlert siInitSDTblErr siInitSPTblErr siInitVBLQsErr sktClosedErr slotNumErr smBadBoardId smBadRefId smBadsList smBadsPtrErr smBLFieldBad smBlkMoveErr smBusErrTO smByteLanesErr smCkStatusErr smCodeRevErr smCPUErr smCRCFail smDisDrvrNamErr smDisposePErr smEmptySlot smFHBlockRdErr smFormatErr smGetDrvrNamErr smGetPRErr smInitStatVErr smInitTblErr smLWTstBad smNewPErr smNilsBlockErr smNoBoardId smNoBoardsRsrc smNoDir smNoGoodOpens smNoJmpTbl smNoMoresRsrcs smNosInfoArray smOffsetErr smPRAMInitErr smPriInitErr smRecNotFnd smReservedErr smResrvErr smRevisionErr smSDMInitErr smSelOOBErr smsGetDrvrErr smSlotOOBErr smsPointerNil smSRTInitErr smSRTOvrFlErr smUnExBusErr spdAdjErr statusErr strUserBreak svDisabled svTempDisable swOverrunErr teScrapSizeErr tk0BadErr tmfoErr tmwdoErr tooManyReqs tooManySkts twoSideErr unimpErr unitEmptyErr unitTblFullErr updPixMemErr userBreak userCanceledErr verErr vLckdErr volGoneErr volOffLinErr volOnLinErr vTypErr wPrErr wrgVolTypErr writErr wrPermErr wrUnderrun æKY qErr æFp Errors.p æT CONST æD qErr = -1; {queue element not found during deletion} æC æKY vTypErr æFp Errors.p æT CONST æD vTypErr = -2; {invalid queue element} æC æKY corErr æFp Errors.p æT CONST æD corErr = -3; {core routine number out of range} æC æKY unimpErr æFp Errors.p æT CONST æD unimpErr = -4; {unimplemented core routine} æC æKY seNoDB æFp Errors.p æT CONST æD seNoDB = -8; {no debugger installed to handle debugger command} æC æKY controlErr æFp Errors.p æT CONST æD controlErr = -17; {I/O System Errors} æC æKY statusErr æFp Errors.p æT CONST æD statusErr = -18; {I/O System Errors} æC æKY readErr æFp Errors.p æT CONST æD readErr = -19; {I/O System Errors} æC æKY writErr æFp Errors.p æT CONST æD writErr = -20; {I/O System Errors} æC æKY badUnitErr æFp Errors.p æT CONST æD badUnitErr = -21; {I/O System Errors} æC æKY unitEmptyErr æFp Errors.p æT CONST æD unitEmptyErr = -22; {I/O System Errors} æC æKY openErr æFp Errors.p æT CONST æD openErr = -23; {I/O System Errors} æC æKY closErr æFp Errors.p æT CONST æD closErr = -24; {I/O System Errors} æC æKY dRemovErr æFp Errors.p æT CONST æD dRemovErr = -25; {tried to remove an open driver} æC æKY dInstErr æFp Errors.p æT CONST æD dInstErr = -26; {DrvrInstall couldn't find driver in resources } æC æKY abortErr æFp Errors.p æT CONST æD abortErr = -27; {IO call aborted by KillIO} æC æKY iIOAbortErr æFp Errors.p æT CONST æD iIOAbortErr = -27; {IO abort error (Printing Manager)} æC æKY notOpenErr æFp Errors.p æT CONST æD notOpenErr = -28; {Couldn't rd/wr/ctl/sts cause driver not opened} æC æKY dirFulErr æFp Errors.p æT CONST æD dirFulErr = -33; {Directory full} æC æKY dskFulErr æFp Errors.p æT CONST æD dskFulErr = -34; {disk full} æC æKY nsvErr æFp Errors.p æT CONST æD nsvErr = -35; {no such volume} æC æKY ioErr æFp Errors.p æT CONST æD ioErr = -36; {I/O error (bummers)} æC æKY bdNamErr æFp Errors.p æT CONST æD bdNamErr = -37; {there may be no bad names in the final system!} æC æKY fnOpnErr æFp Errors.p æT CONST æD fnOpnErr = -38; {File not open} æC æKY eofErr æFp Errors.p æT CONST æD eofErr = -39; {End of file} æC æKY posErr æFp Errors.p æT CONST æD posErr = -40; {tried to position to before start of file (r/w)} æC æKY mFulErr æFp Errors.p æT CONST æD mFulErr = -41; {memory full (open) or file won't fit (load)} æC æKY tmfoErr æFp Errors.p æT CONST æD tmfoErr = -42; {too many files open} æC æKY fnfErr æFp Errors.p æT CONST æD fnfErr = -43; {File not found} æC æKY wPrErr æFp Errors.p æT CONST æD wPrErr = -44; {diskette is write protected.} æC æKY fLckdErr æFp Errors.p æT CONST æD fLckdErr = -45; {file is locked} æC æKY vLckdErr æFp Errors.p æT CONST æD vLckdErr = -46; {volume is locked} æC æKY fBsyErr æFp Errors.p æT CONST æD fBsyErr = -47; {File is busy (delete)} æC æKY dupFNErr æFp Errors.p æT CONST æD dupFNErr = -48; {duplicate filename (rename)} æC æKY opWrErr æFp Errors.p æT CONST æD opWrErr = -49; {file already open with with write permission} æC æKY paramErr æFp Errors.p æT CONST æD paramErr = -50; {error in user parameter list} æC æKY rfNumErr æFp Errors.p æT CONST æD rfNumErr = -51; {refnum error} æC æKY gfpErr æFp Errors.p æT CONST æD gfpErr = -52; {get file position error} æC æKY volOffLinErr æFp Errors.p æT CONST æD volOffLinErr = -53; {volume not on line error (was Ejected)} æC æKY permErr æFp Errors.p æT CONST æD permErr = -54; {permissions error (on file open)} æC æKY pixMapTooDeepErr æFp Errors.p æT CONST æD pixMapTooDeepErr = -148; æC æKY volOnLinErr æFp Errors.p æT CONST æD volOnLinErr = -55; {drive volume already on-line at MountVol} æC æKY nsDrvErr æFp Errors.p æT CONST æD nsDrvErr = -56; {no such drive (tried to mount a bad drive num)} æC æKY noMacDskErr æFp Errors.p æT CONST æD noMacDskErr = -57; {not a mac diskette (sig bytes are wrong)} æC æKY extFSErr æFp Errors.p æT CONST æD extFSErr = -58; {volume in question belongs to an external fs} æC æKY fsRnErr æFp Errors.p æT CONST æD fsRnErr = -59; {file system internal error:during rename the old entry was deleted but could not be restored.} æC æKY badMDBErr æFp Errors.p æT CONST æD badMDBErr = -60; {bad master directory block} æC æKY wrPermErr æFp Errors.p æT CONST æD wrPermErr = -61; {write permissions error} æC æKY fontDecError æFp Errors.p æT CONST æD fontDecError = -64; {error during font declaration} æC æKY lastDskErr æFp Errors.p æT CONST æD lastDskErr = -64; {I/O System Errors} æC æKY noDriveErr æFp Errors.p æT CONST æD noDriveErr = -64; {drive not installed} æC æKY offLinErr æFp Errors.p æT CONST æD offLinErr = -65; {r/w requested for an off-line drive} æC æKY fontNotDeclared æFp Errors.p æT CONST æD fontNotDeclared = -65; {font not declared} æC æKY noNybErr æFp Errors.p æT CONST æD noNybErr = -66; {couldn't find 5 nybbles in 200 tries} æC æKY fontSubErr æFp Errors.p æT CONST æD fontSubErr = -66; {font substitution occured} æC æKY noAdrMkErr æFp Errors.p æT CONST æD noAdrMkErr = -67; {couldn't find valid addr mark} æC æKY dataVerErr æFp Errors.p æT CONST æD dataVerErr = -68; {read verify compare failed} æC æKY badCksmErr æFp Errors.p æT CONST æD badCksmErr = -69; {addr mark checksum didn't check} æC æKY badBtSlpErr æFp Errors.p æT CONST æD badBtSlpErr = -70; {bad addr mark bit slip nibbles} æC æKY noDtaMkErr æFp Errors.p æT CONST æD noDtaMkErr = -71; {couldn't find a data mark header} æC æKY badDCksum æFp Errors.p æT CONST æD badDCksum = -72; {bad data mark checksum} æC æKY badDBtSlp æFp Errors.p æT CONST æD badDBtSlp = -73; {bad data mark bit slip nibbles} æC æKY wrUnderrun æFp Errors.p æT CONST æD wrUnderrun = -74; {write underrun occurred} æC æKY cantStepErr æFp Errors.p æT CONST æD cantStepErr = -75; {step handshake failed} æC æKY tk0BadErr æFp Errors.p æT CONST æD tk0BadErr = -76; {track 0 detect doesn't change} æC æKY initIWMErr æFp Errors.p æT CONST æD initIWMErr = -77; {unable to initialize IWM} æC æKY twoSideErr æFp Errors.p æT CONST æD twoSideErr = -78; {tried to read 2nd side on a 1-sided drive} æC æKY spdAdjErr æFp Errors.p æT CONST æD spdAdjErr = -79; {unable to correctly adjust disk speed} æC æKY seekErr æFp Errors.p æT CONST æD seekErr = -80; {track number wrong on address mark} æC æKY sectNFErr æFp Errors.p æT CONST æD sectNFErr = -81; {sector number never found on a track} æC æKY fmt1Err æFp Errors.p æT CONST æD fmt1Err = -82; {can't find sector 0 after track format} æC æKY fmt2Err æFp Errors.p æT CONST æD fmt2Err = -83; {can't get enough sync} æC æKY verErr æFp Errors.p æT CONST æD verErr = -84; {track failed to verify} æC æKY firstDskErr æFp Errors.p æT CONST æD firstDskErr = -84; {I/O System Errors} æC æKY clkRdErr æFp Errors.p æT CONST æD clkRdErr = -85; {unable to read same clock value twice} æC æKY clkWrErr æFp Errors.p æT CONST æD clkWrErr = -86; {time written did not verify} æC æKY prWrErr æFp Errors.p æT CONST æD prWrErr = -87; {parameter ram written didn't read-verify} æC æKY prInitErr æFp Errors.p æT CONST æD prInitErr = -88; {InitUtil found the parameter ram uninitialized} æC æKY rcvrErr æFp Errors.p æT CONST æD rcvrErr = -89; {SCC receiver error (framing; parity; OR)} æC æKY breakRecd æFp Errors.p æT CONST æD breakRecd = -90; {Break received (SCC)} æC æKY ddpSktErr æFp Errors.p æT CONST æD ddpSktErr = -91; {error in soket number} æC æKY ddpLenErr æFp Errors.p æT CONST æD ddpLenErr = -92; {data length too big} æC æKY noBridgeErr æFp Errors.p æT CONST æD noBridgeErr = -93; {no network bridge for non-local send} æC æKY lapProtErr æFp Errors.p æT CONST æD lapProtErr = -94; {error in attaching/detaching protocol} æC æKY excessCollsns æFp Errors.p æT CONST æD excessCollsns = -95; {excessive collisions on write} æC æKY portInUse æFp Errors.p æT CONST æD portInUse = -97; {driver Open error code (port is in use)} æC æKY portNotCf æFp Errors.p æT CONST æD portNotCf = -98; {driver Open error code (parameter RAM not configured for this connection)} æC æKY memROZErr æFp Errors.p æT CONST æD memROZErr = -99; {hard error in ROZ} æC æKY noScrapErr æFp Errors.p æT CONST æD noScrapErr = -100; {No scrap exists error} æC æKY noTypeErr æFp Errors.p æT CONST æD noTypeErr = -102; {No object of that type in scrap} æC æKY memFullErr æFp Errors.p æT CONST æD memFullErr = -108; {Not enough room in heap zone} æC æKY nilHandleErr æFp Errors.p æT CONST æD nilHandleErr = -109; {Master Pointer was NIL in HandleZone or other} æC æKY memAdrErr æFp Errors.p æT CONST æD memAdrErr = -110; {address was odd; or out of range} æC æKY memWZErr æFp Errors.p æT CONST æD memWZErr = -111; {WhichZone failed (applied to free block)} æC æKY memPurErr æFp Errors.p æT CONST æD memPurErr = -112; {trying to purge a locked or non-purgeable block} æC æKY memAZErr æFp Errors.p æT CONST æD memAZErr = -113; {Address in zone check failed} æC æKY memPCErr æFp Errors.p æT CONST æD memPCErr = -114; {Pointer Check failed} æC æKY memBCErr æFp Errors.p æT CONST æD memBCErr = -115; {Block Check failed} æC æKY memSCErr æFp Errors.p æT CONST æD memSCErr = -116; {Size Check failed} æC æKY memLockedErr æFp Errors.p æT CONST æD memLockedErr = -117; {trying to move a locked block (MoveHHi)} æC æKY dirNFErr æFp Errors.p æT CONST æD dirNFErr = -120; {Directory not found} æC æKY tmwdoErr æFp Errors.p æT CONST æD tmwdoErr = -121; {No free WDCB available} æC æKY badMovErr æFp Errors.p æT CONST æD badMovErr = -122; {Move into offspring error} æC æKY wrgVolTypErr æFp Errors.p æT CONST æD wrgVolTypErr = -123; {Wrong volume type error [operation not supported for MFS]} æC æKY volGoneErr æFp Errors.p æT CONST æD volGoneErr = -124; {Server volume has been disconnected.} æC æKY fsDSIntErr æFp Errors.p æT CONST æD fsDSIntErr = -127; {Internal file system error} æC æKY userCanceledErr æFp Errors.p æT CONST æD userCanceledErr = -128; æC æKY fidNotFound æFp Errors.p æT CONST æD fidNotFound = -1300; {no file thread exists.} æC æKY fidExists æFp Errors.p æT CONST æD fidExists = -1301; {file id already exists} æC æKY NotAFileErr æFp Errors.p æT CONST æD NotAFileErr = -1302; {directory specified} æC æKY DiffVolErr æFp Errors.p æT CONST æD DiffVolErr = -1303; {files on different volumes} æC æKY catChangedErr æFp Errors.p æT CONST æD catChangedErr = -1304; {the catalog has been modified} æC æKY resNotFound æFp Errors.p æT CONST æD resNotFound = -192; {Resource not found} æC æKY resFNotFound æFp Errors.p æT CONST æD resFNotFound = -193; {Resource file not found} æC æKY addResFailed æFp Errors.p æT CONST æD addResFailed = -194; {AddResource failed} æC æKY addRefFailed æFp Errors.p æT CONST æD addRefFailed = -195; {AddReference failed} æC æKY rmvResFailed æFp Errors.p æT CONST æD rmvResFailed = -196; {RmveResource failed} æC æKY rmvRefFailed æFp Errors.p æT CONST æD rmvRefFailed = -197; {RmveReference failed} æC æKY resAttrErr æFp Errors.p æT CONST æD resAttrErr = -198; {attribute inconsistent with operation} æC æKY mapReadErr æFp Errors.p æT CONST æD mapReadErr = -199; {map inconsistent with operation} æC æKY editionMgrInitErr æFp Errors.p æT CONST æD editionMgrInitErr = -450; {edition manager not inited by this app} æC æKY badSectionErr æFp Errors.p æT CONST æD badSectionErr = -451; {not a valid SectionRecord} æC æKY notRegisteredSectionErr æFp Errors.p æT CONST æD notRegisteredSectionErr = -452; {not a registered SectionRecord} æC æKY badEditionFileErr æFp Errors.p æT CONST æD badEditionFileErr = -453; {edition file is corrupt} æC æKY badSubPartErr æFp Errors.p æT CONST æD badSubPartErr = -454; {can not use sub parts in this release} æC æKY multiplePublisherWrn æFp Errors.p æT CONST æD multiplePublisherWrn = -460; {A Publisher is already registered for that container} æC æKY containerNotFoundWrn æFp Errors.p æT CONST æD containerNotFoundWrn = -461; {could not find editionContainer at this time} æC æKY containerAlreadyOpenWrn æFp Errors.p æT CONST æD containerAlreadyOpenWrn = -462; {container already opened by this section} æC æKY notThePublisherWrn æFp Errors.p æT CONST æD notThePublisherWrn = -463; {not the first registered publisher for that container} æC æKY userBreak æFp Errors.p æT CONST æD userBreak = -490; {user debugger break} æC æKY strUserBreak æFp Errors.p æT CONST æD strUserBreak = -491; {user debugger break; display string on stack} æC æKY exUserBreak æFp Errors.p æT CONST æD exUserBreak = -492; {user debugger break; execute debugger commands on stack} æC æKY nbpBuffOvr æFp Errors.p æT CONST æD nbpBuffOvr = -1024; {Buffer overflow in LookupName} æC æKY nbpNoConfirm æFp Errors.p æT CONST æD nbpNoConfirm = -1025; æC æKY nbpConfDiff æFp Errors.p æT CONST æD nbpConfDiff = -1026; {Name confirmed at different socket} æC æKY nbpDuplicate æFp Errors.p æT CONST æD nbpDuplicate = -1027; {Duplicate name exists already} æC æKY nbpNotFound æFp Errors.p æT CONST æD nbpNotFound = -1028; {Name not found on remove} æC æKY nbpNISErr æFp Errors.p æT CONST æD nbpNISErr = -1029; {Error trying to open the NIS} æC æKY aspBadVersNum æFp Errors.p æT CONST æD aspBadVersNum = -1066; {Server cannot support this ASP version} æC æKY aspBufTooSmall æFp Errors.p æT CONST æD aspBufTooSmall = -1067; {Buffer too small} æC æKY aspNoMoreSess æFp Errors.p æT CONST æD aspNoMoreSess = -1068; {No more sessions on server} æC æKY aspNoServers æFp Errors.p æT CONST æD aspNoServers = -1069; {No servers at that address} æC æKY aspParamErr æFp Errors.p æT CONST æD aspParamErr = -1070; {Parameter error} æC æKY aspServerBusy æFp Errors.p æT CONST æD aspServerBusy = -1071; {Server cannot open another session} æC æKY aspSessClosed æFp Errors.p æT CONST æD aspSessClosed = -1072; {Session closed} æC æKY aspSizeErr æFp Errors.p æT CONST æD aspSizeErr = -1073; {Command block too big} æC æKY aspTooMany æFp Errors.p æT CONST æD aspTooMany = -1074; {Too many clients (server error)} æC æKY aspNoAck æFp Errors.p æT CONST æD aspNoAck = -1075; {No ack on attention request (server err)} æC æKY reqFailed æFp Errors.p æT CONST æD reqFailed = -1096; æC æKY tooManyReqs æFp Errors.p æT CONST æD tooManyReqs = -1097; æC æKY tooManySkts æFp Errors.p æT CONST æD tooManySkts = -1098; æC æKY badATPSkt æFp Errors.p æT CONST æD badATPSkt = -1099; æC æKY badBuffNum æFp Errors.p æT CONST æD badBuffNum = -1100; æC æKY noRelErr æFp Errors.p æT CONST æD noRelErr = -1101; æC æKY cbNotFound æFp Errors.p æT CONST æD cbNotFound = -1102; æC æKY noSendResp æFp Errors.p æT CONST æD noSendResp = -1103; æC æKY noDataArea æFp Errors.p æT CONST æD noDataArea = -1104; æC æKY reqAborted æFp Errors.p æT CONST æD reqAborted = -1105; æC æKY buf2SmallErr æFp Errors.p æT CONST æD buf2SmallErr = -3101; æC æKY noMPPErr æFp Errors.p æT CONST æD noMPPErr = -3102; æC æKY ckSumErr æFp Errors.p æT CONST æD ckSumErr = -3103; æC æKY extractErr æFp Errors.p æT CONST æD extractErr = -3104; æC æKY readQErr æFp Errors.p æT CONST æD readQErr = -3105; æC æKY atpLenErr æFp Errors.p æT CONST æD atpLenErr = -3106; æC æKY atpBadRsp æFp Errors.p æT CONST æD atpBadRsp = -3107; æC æKY recNotFnd æFp Errors.p æT CONST æD recNotFnd = -3108; æC æKY sktClosedErr æFp Errors.p æT CONST æD sktClosedErr = -3109; æC æKY afpAccessDenied æFp Errors.p æT CONST æD afpAccessDenied = -5000; æC æKY afpAuthContinue æFp Errors.p æT CONST æD afpAuthContinue = -5001; æC æKY afpBadUAM æFp Errors.p æT CONST æD afpBadUAM = -5002; æC æKY afpBadVersNum æFp Errors.p æT CONST æD afpBadVersNum = -5003; æC æKY afpBitmapErr æFp Errors.p æT CONST æD afpBitmapErr = -5004; æC æKY afpCantMove æFp Errors.p æT CONST æD afpCantMove = -5005; æC æKY afpDenyConflict æFp Errors.p æT CONST æD afpDenyConflict = -5006; æC æKY afpDirNotEmpty æFp Errors.p æT CONST æD afpDirNotEmpty = -5007; æC æKY afpDiskFull æFp Errors.p æT CONST æD afpDiskFull = -5008; æC æKY afpEofError æFp Errors.p æT CONST æD afpEofError = -5009; æC æKY afpFileBusy æFp Errors.p æT CONST æD afpFileBusy = -5010; æC æKY afpFlatVol æFp Errors.p æT CONST æD afpFlatVol = -5011; æC æKY afpItemNotFound æFp Errors.p æT CONST æD afpItemNotFound = -5012; æC æKY memROZWarn æFp Errors.p æT CONST æD memROZWarn = -99; {soft error in ROZ} æC æKY afpLockErr æFp Errors.p æT CONST æD afpLockErr = -5013; æC æKY afpMiscErr æFp Errors.p æT CONST æD afpMiscErr = -5014; æC æKY afpNoMoreLocks æFp Errors.p æT CONST æD afpNoMoreLocks = -5015; æC æKY afpNoServer æFp Errors.p æT CONST æD afpNoServer = -5016; æC æKY afpObjectExists æFp Errors.p æT CONST æD afpObjectExists = -5017; æC æKY afpObjectNotFound æFp Errors.p æT CONST æD afpObjectNotFound = -5018; æC æKY afpParmErr æFp Errors.p æT CONST æD afpParmErr = -5019; æC æKY afpRangeNotLocked æFp Errors.p æT CONST æD afpRangeNotLocked = -5020; æC æKY afpRangeOverlap æFp Errors.p æT CONST æD afpRangeOverlap = -5021; æC æKY afpSessClosed æFp Errors.p æT CONST æD afpSessClosed = -5022; æC æKY afpUserNotAuth æFp Errors.p æT CONST æD afpUserNotAuth = -5023; æC æKY afpCallNotSupported æFp Errors.p æT CONST æD afpCallNotSupported = -5024; æC æKY afpObjectTypeErr æFp Errors.p æT CONST æD afpObjectTypeErr = -5025; æC æKY afpTooManyFilesOpen æFp Errors.p æT CONST æD afpTooManyFilesOpen = -5026; æC æKY afpServerGoingDown æFp Errors.p æT CONST æD afpServerGoingDown = -5027; æC æKY afpCantRename æFp Errors.p æT CONST æD afpCantRename = -5028; æC æKY afpDirNotFound æFp Errors.p æT CONST æD afpDirNotFound = -5029; æC æKY afpIconTypeError æFp Errors.p æT CONST æD afpIconTypeError = -5030; æC æKY afpVolLocked æFp Errors.p æT CONST æD afpVolLocked = -5031; {Volume is Read-Only} æC æKY afpObjectLocked æFp Errors.p æT CONST æD afpObjectLocked = -5032; {Object is M/R/D/W inhibited} æC æKY envNotPresent æFp Errors.p æT CONST æD envNotPresent = -5500; {returned by glue.} æC æKY envBadVers æFp Errors.p æT CONST æD envBadVers = -5501; {Version non-positive} æC æKY envVersTooBig æFp Errors.p æT CONST æD envVersTooBig = -5502; {Version bigger than call can handle} æC æKY evtNotEnb æFp Errors.p æT CONST æD evtNotEnb = 1; {event not enabled at PostEvent} æC æKY dsSysErr æFp Errors.p æT CONST æD dsSysErr = 32767; {general system error} æC æKY dsBusError æFp Errors.p æT CONST æD dsBusError = 1; {bus error } æC æKY dsAddressErr æFp Errors.p æT CONST æD dsAddressErr = 2; {address error} æC æKY dsIllInstErr æFp Errors.p æT CONST æD dsIllInstErr = 3; {illegal instruction error} æC æKY dsZeroDivErr æFp Errors.p æT CONST æD dsZeroDivErr = 4; {zero divide error} æC æKY dsChkErr æFp Errors.p æT CONST æD dsChkErr = 5; {check trap error} æC æKY dsOvflowErr æFp Errors.p æT CONST æD dsOvflowErr = 6; {overflow trap error} æC æKY dsPrivErr æFp Errors.p æT CONST æD dsPrivErr = 7; {privilege violation error} æC æKY dsTraceErr æFp Errors.p æT CONST æD dsTraceErr = 8; {trace mode error} æC æKY dsLineAErr æFp Errors.p æT CONST æD dsLineAErr = 9; {line 1010 trap error} æC æKY dsLineFErr æFp Errors.p æT CONST æD dsLineFErr = 10; {line 1111 trap error} æC æKY dsMiscErr æFp Errors.p æT CONST æD dsMiscErr = 11; {miscellaneous hardware exception error} æC æKY dsCoreErr æFp Errors.p æT CONST æD dsCoreErr = 12; {unimplemented core routine error} æC æKY dsIrqErr æFp Errors.p æT CONST æD dsIrqErr = 13; {uninstalled interrupt error} æC æKY dsIOCoreErr æFp Errors.p æT CONST æD dsIOCoreErr = 14; {IO Core Error} æC æKY dsLoadErr æFp Errors.p æT CONST æD dsLoadErr = 15; {Segment Loader Error} æC æKY dsFPErr æFp Errors.p æT CONST æD dsFPErr = 16; {Floating point error} æC æKY dsNoPackErr æFp Errors.p æT CONST æD dsNoPackErr = 17; {package 0 not present} æC æKY dsNoPk1 æFp Errors.p æT CONST æD dsNoPk1 = 18; {package 1 not present} æC æKY dsNoPk2 æFp Errors.p æT CONST æD dsNoPk2 = 19; {package 2 not present} æC æKY dsNoPk3 æFp Errors.p æT CONST æD dsNoPk3 = 20; {package 3 not present} æC æKY dsNoPk4 æFp Errors.p æT CONST æD dsNoPk4 = 21; {package 4 not present} æC æKY dsNoPk5 æFp Errors.p æT CONST æD dsNoPk5 = 22; {package 5 not present} æC æKY dsNoPk6 æFp Errors.p æT CONST æD dsNoPk6 = 23; {package 6 not present} æC æKY dsNoPk7 æFp Errors.p æT CONST æD dsNoPk7 = 24; {package 7 not present} æC æKY dsMemFullErr æFp Errors.p æT CONST æD dsMemFullErr = 25; {out of memory!} æC æKY dsBadLaunch æFp Errors.p æT CONST æD dsBadLaunch = 26; {can't launch file} æC æKY dsFSErr æFp Errors.p æT CONST æD dsFSErr = 27; {file system map has been trashed} æC æKY dsStknHeap æFp Errors.p æT CONST æD dsStknHeap = 28; {stack has moved into application heap} æC æKY dsReinsert æFp Errors.p æT CONST æD dsReinsert = 30; {request user to reinsert off-line volume} æC æKY dsNotThe1 æFp Errors.p æT CONST æD dsNotThe1 = 31; {not the disk I wanted} æC æKY negZcbFreeErr æFp Errors.p æT CONST æD negZcbFreeErr = 33; {ZcbFree has gone negative} æC æKY dsGreeting æFp Errors.p æT CONST æD dsGreeting = 40; {welcome to Macintosh greeting} æC æKY dsFinderErr æFp Errors.p æT CONST æD dsFinderErr = 41; {can't load the Finder error} æC æKY shutDownAlert æFp Errors.p æT CONST æD shutDownAlert = 42; {handled like a shutdown error} æC æKY menuPrgErr æFp Errors.p æT CONST æD menuPrgErr = 84; {happens when a menu is purged} æC æKY swOverrunErr æFp Errors.p æT CONST æD swOverrunErr = 1; {serial driver error masks} æC æKY parityErr æFp Errors.p æT CONST æD parityErr = 16; {serial driver error masks} æC æKY hwOverrunErr æFp Errors.p æT CONST æD hwOverrunErr = 32; {serial driver error masks} æC æKY framingErr æFp Errors.p æT CONST æD framingErr = 64; {serial driver error masks} æC æKY cMatchErr æFp Errors.p æT CONST æD cMatchErr = -150; {Color2Index failed to find an index} æC æKY cTempMemErr æFp Errors.p æT CONST æD cTempMemErr = -151; {failed to allocate memory for temporary structures} æC æKY cNoMemErr æFp Errors.p æT CONST æD cNoMemErr = -152; {failed to allocate memory for structure} æC æKY cRangeErr æFp Errors.p æT CONST æD cRangeErr = -153; {range error on colorTable request} æC æKY cProtectErr æFp Errors.p æT CONST æD cProtectErr = -154; {colorTable entry protection violation} æC æKY cDevErr æFp Errors.p æT CONST æD cDevErr = -155; {invalid type of graphics device} æC æKY cResErr æFp Errors.p æT CONST æD cResErr = -156; {invalid resolution for MakeITable} æC æKY unitTblFullErr æFp Errors.p æT CONST æD unitTblFullErr = -29; {unit table has no more entries} æC æKY dceExtErr æFp Errors.p æT CONST æD dceExtErr = -30; {dce extension error} æC æKY dsBadSlotInt æFp Errors.p æT CONST æD dsBadSlotInt = 51; {unserviceable slot interrupt} æC æKY dsBadSANEopcode æFp Errors.p æT CONST æD dsBadSANEopcode = 81; {bad opcode given to SANE Pack4} æC æKY dsNoPatch æFp Errors.p æT CONST æD dsNoPatch = 98; {Can't patch for particular Model Mac} æC æKY dsBadPatch æFp Errors.p æT CONST æD dsBadPatch = 99; {Can't load patch resource} æC æKY updPixMemErr æFp Errors.p æT CONST æD updPixMemErr = -125; {insufficient memory to update a pixmap} æC æKY mBarNFnd æFp Errors.p æT CONST æD mBarNFnd = -126; {system error code for MBDF not found} æC æKY hMenuFindErr æFp Errors.p æT CONST æD hMenuFindErr = -127; {could not find HMenu's parent in MenuKey} æC æKY noHardware æFp Errors.p æT CONST æD noHardware = -200; {Sound Manager Error Returns} æC æKY notEnoughHardware æFp Errors.p æT CONST æD notEnoughHardware = -201; {Sound Manager Error Returns} æC æKY queueFull æFp Errors.p æT CONST æD queueFull = -203; {Sound Manager Error Returns} æC æKY resProblem æFp Errors.p æT CONST æD resProblem = -204; {Sound Manager Error Returns} æC æKY badChannel æFp Errors.p æT CONST æD badChannel = -205; {Sound Manager Error Returns} æC æKY badFormat æFp Errors.p æT CONST æD badFormat = -206; {Sound Manager Error Returns} æC æKY smSDMInitErr æFp Errors.p æT CONST æD smSDMInitErr = -290; {Error; SDM could not be initialized.} æC æKY smSRTInitErr æFp Errors.p æT CONST æD smSRTInitErr = -291; {Error; Slot Resource Table could not be initialized.} æC æKY smPRAMInitErr æFp Errors.p æT CONST æD smPRAMInitErr = -292; {Error; Slot Resource Table could not be initialized.} æC æKY smPriInitErr æFp Errors.p æT CONST æD smPriInitErr = -293; {Error; Cards could not be initialized.} æC æKY nmTypErr æFp Errors.p æT CONST æD nmTypErr = -299; æC æKY smEmptySlot æFp Errors.p æT CONST æD smEmptySlot = -300; {No card in slot} æC æKY smCRCFail æFp Errors.p æT CONST æD smCRCFail = -301; {CRC check failed for declaration data} æC æKY smFormatErr æFp Errors.p æT CONST æD smFormatErr = -302; {FHeader Format is not Apple's} æC æKY smRevisionErr æFp Errors.p æT CONST æD smRevisionErr = -303; {Wrong revison level} æC æKY smNoDir æFp Errors.p æT CONST æD smNoDir = -304; {Directory offset is Nil } æC æKY smLWTstBad æFp Errors.p æT CONST æD smLWTstBad = -305; {Long Word test field <> $5A932BC7.} æC æKY smNosInfoArray æFp Errors.p æT CONST æD smNosInfoArray = -306; {No sInfoArray. Memory Mgr error.} æC æKY smResrvErr æFp Errors.p æT CONST æD smResrvErr = -307; {Fatal reserved error. Resreved field <> 0.} æC æKY smUnExBusErr æFp Errors.p æT CONST æD smUnExBusErr = -308; {Unexpected BusError} æC æKY smBLFieldBad æFp Errors.p æT CONST æD smBLFieldBad = -309; {ByteLanes field was bad.} æC æKY smFHBlockRdErr æFp Errors.p æT CONST æD smFHBlockRdErr = -310; {Error occured during _sGetFHeader.} æC æKY smDisposePErr æFp Errors.p æT CONST æD smDisposePErr = -312; {_DisposePointer error} æC æKY smNoBoardsRsrc æFp Errors.p æT CONST æD smNoBoardsRsrc = -313; {No Board sResource.} æC æKY smGetPRErr æFp Errors.p æT CONST æD smGetPRErr = -314; {Error occured during _sGetPRAMRec (See SIMStatus).} æC æKY smNoBoardId æFp Errors.p æT CONST æD smNoBoardId = -315; {No Board Id.} æC æKY smInitStatVErr æFp Errors.p æT CONST æD smInitStatVErr = -316; {The InitStatusV field was negative after primary or secondary init.} æC æKY smInitTblErr æFp Errors.p æT CONST æD smInitTblErr = -317; {An error occured while trying to initialize the Slot Resource Table.} æC æKY smNoJmpTbl æFp Errors.p æT CONST æD smNoJmpTbl = -318; {SDM jump table could not be created.} æC æKY smBadBoardId æFp Errors.p æT CONST æD smBadBoardId = -319; {BoardId was wrong; re-init the PRAM record.} æC æKY smBusErrTO æFp Errors.p æT CONST æD smBusErrTO = -320; {BusError time out.} æC æKY smBadRefId æFp Errors.p æT CONST æD smBadRefId = -330; {Reference Id not found in List} æC æKY smBadsList æFp Errors.p æT CONST æD smBadsList = -331; {Bad sList: Id1 < Id2 < Id3 ...format is not followed.} æC æKY smReservedErr æFp Errors.p æT CONST æD smReservedErr = -332; {Reserved field not zero} æC æKY smCodeRevErr æFp Errors.p æT CONST æD smCodeRevErr = -333; {Code revision is wrong} æC æKY smCPUErr æFp Errors.p æT CONST æD smCPUErr = -334; {Code revision is wrong} æC æKY smsPointerNil æFp Errors.p æT CONST æD smsPointerNil = -335; {LPointer is nil From sOffsetData. If this error occurs; check sInfo rec for more information.} æC æKY smNilsBlockErr æFp Errors.p æT CONST æD smNilsBlockErr = -336; {Nil sBlock error (Dont allocate and try to use a nil sBlock)} æC æKY smSlotOOBErr æFp Errors.p æT CONST æD smSlotOOBErr = -337; {Slot out of bounds error} æC æKY smSelOOBErr æFp Errors.p æT CONST æD smSelOOBErr = -338; {Selector out of bounds error} æC æKY smNewPErr æFp Errors.p æT CONST æD smNewPErr = -339; {_NewPtr error} æC æKY smBlkMoveErr æFp Errors.p æT CONST æD smBlkMoveErr = -340; {_BlockMove error} æC æKY smCkStatusErr æFp Errors.p æT CONST æD smCkStatusErr = -341; {Status of slot = fail.} æC æKY smGetDrvrNamErr æFp Errors.p æT CONST æD smGetDrvrNamErr = -342; {Error occured during _sGetDrvrName.} æC æKY smDisDrvrNamErr æFp Errors.p æT CONST æD smDisDrvrNamErr = -343; {Error occured during _sDisDrvrName.} æC æKY smNoMoresRsrcs æFp Errors.p æT CONST æD smNoMoresRsrcs = -344; {No more sResources} æC æKY smsGetDrvrErr æFp Errors.p æT CONST æD smsGetDrvrErr = -345; {Error occurred during _sGetDriver.} æC æKY smBadsPtrErr æFp Errors.p æT CONST æD smBadsPtrErr = -346; {Bad pointer was passed to sCalcsPointer} æC æKY smByteLanesErr æFp Errors.p æT CONST æD smByteLanesErr = -347; {NumByteLanes was determined to be zero.} æC æKY smOffsetErr æFp Errors.p æT CONST æD smOffsetErr = -348; {Offset was too big (temporary error} æC æKY smNoGoodOpens æFp Errors.p æT CONST æD smNoGoodOpens = -349; {No opens were successfull in the loop.} æC æKY smSRTOvrFlErr æFp Errors.p æT CONST æD smSRTOvrFlErr = -350; {SRT over flow.} æC æKY smRecNotFnd æFp Errors.p æT CONST æD smRecNotFnd = -351; {Record not found in the SRT.} æC æKY slotNumErr æFp Errors.p æT CONST æD slotNumErr = -360; {invalid slot # error} æC æKY gcrOnMFMErr æFp Errors.p æT CONST æD gcrOnMFMErr = -400; {gcr format on high density media error} æC æKY rgnTooBigErr æFp Errors.p æT CONST æD rgnTooBigErr = -500; æC æKY teScrapSizeErr æFp Errors.p æT CONST æD teScrapSizeErr = -501; {scrap item too big for text edit record} æC æKY hwParamErr æFp Errors.p æT CONST æD hwParamErr = -502; {bad selector for _HWPriv} æC æKY svTempDisable æFp Errors.p æT CONST æD { The following errors are for primary or secondary init code. The errors are logged in the vendor status field of the sInfo record. Normally the vendor error is not Apple's concern, but a special error is needed to patch secondary inits. } svTempDisable = -32768; {Temporarily disable card but run primary init.} æC æKY svDisabled æFp Errors.p æT CONST æD svDisabled = -32640; {Reserve range -32640 to -32768 for Apple temp disables.} æC æKY siInitSDTblErr æFp Errors.p æT CONST æD siInitSDTblErr = 1; {slot int dispatch table could not be initialized.} æC æKY siInitVBLQsErr æFp Errors.p æT CONST æD siInitVBLQsErr = 2; {VBLqueues for all slots could not be initialized.} æC æKY siInitSPTblErr æFp Errors.p æT CONST æD siInitSPTblErr = 3; {slot priority table could not be initialized.} æC æKY sdmJTInitErr æFp Errors.p æT CONST æD sdmJTInitErr = 10; {SDM Jump Table could not be initialized.} æC æKY sdmInitErr æFp Errors.p æT CONST æD sdmInitErr = 11; {SDM could not be initialized.} æC æKY sdmSRTInitErr æFp Errors.p æT CONST æD sdmSRTInitErr = 12; {Slot Resource Table could not be initialized.} æC æKY sdmPRAMInitErr æFp Errors.p æT CONST æD sdmPRAMInitErr = 13; {Slot PRAM could not be initialized.} æC æKY sdmPriInitErr æFp Errors.p æT CONST æD sdmPriInitErr = 14; {Cards could not be initialized.} æC æKY dsMBarNFnd æFp Errors.p æT CONST æD dsMBarNFnd = 85; {Menu Manager Errors} æC æKY dsHMenuFindErr æFp Errors.p æT CONST æD dsHMenuFindErr = 86; {Menu Manager Errors} æC æKY SysError æFp Errors.p æT PROCEDURE æD PROCEDURE SysError(errorCode: INTEGER); INLINE $301F,$A9C9; æDT SysError(errorCode); æMM æRI II-362, V-572 æC _____________________________________________________________________________________ Trap macro _SysError On entry D0: errorCode (word) On exit All registers changed _____________________________________________________________________________________ SysError generates a system error with the ID specified by the errorCode parameter. It takes the following precise steps: 1. It saves all registers and the stack pointer. 2. It stores the system error ID in a global variable (named DSErrCode). 3. It checks to see whether there's a system error alert table in memory (by testing whether the global variable DSAlertTab is 0); if there isn't, it draws the "sad Macintosh" icon. 4. It allocates memory for QuickDraw globals on the stack, initializes QuickDraw, and initializes a grafPort in which the alert box will be drawn. 5. It checks the system error ID. If the system error ID is negative, the alert box isn't redrawn (this is used for system startup alerts, which can display a sequence of consecutive messages in the same box). If the system error ID doesn't correspond to an entry in the system error alert table, the default alert definition at the start of the table will be used, displaying the message "Sorry, a system error occurred". 6. It draws an alert box (in the rectangle specified by the global variable DSAlertRect). 7. If the text definition IDs in the alert definition for this alert aren't 0, it draws both strings. 8. If the icon definition ID in the alert definition isn't 0, it draws the icon. 9. If the procedure definition ID in the alert definition isn't 0, it invokes the procedure with the specified ID. 10. If the button definition ID in the alert definition is 0, it returns control to the procedure that called it (this is used during the disk-switch alert to return control to the File Manager after the "Please insert the disk:" message has been displayed). 11. If there's a resume procedure, it increments the button definition ID by 1. 12. It draws the buttons. 13. It hit-tests the buttons and calls the corresponding procedure code when a button is pressed. If there's no procedure code, it returns to the procedure that called it. User Alerts _____________ ID Explanation 1 Bus error: Invalid memory reference; happens only on a Macintosh XL 2 Address error: Word or long-word reference made to an odd address 3 Illegal instruction: The MC68000 received an instruction it didn't recognize. 4 Zero divide: Signed Divide (DIVS) or Unsigned Divide (DIVU) instruction with a divisor of 0 was executed. 5 Check exception: Check Register Against Bounds (CHK) instruction was executed and failed. Pascal "value out of range" errors are usually reported in this way. 6 TrapV exception: Trap On Overflow (TRAPV) instruction was executed and failed. 7 Privilege violation: Macintosh always runs in supervisor mode; perhaps an erroneous Return From Execution (RTE) instruction was executed. 8 Trace exception: The trace bit in the status register is set. 9 Line 1010 exception: The 1010 trap dispatcher has failed. 10 Line 1111 exception: Unimplemented instruction 11 Miscellaneous exception: All other MC68000 exceptions 12 Unimplemented core routine: An unimplemented trap number was encountered. 13 Spurious interrupt: The interrupt vector table entry for a particular level of interrupt is NIL; usually occurs with level 4, 5, 6, or 7 interrupts. 14 I/O system error: The File Manager is attempting to dequeue an entry from an I/O request queue that has a bad queue type field; perhaps the queue entry is unlocked. Or, the dCtlQHead field was NIL during a Fetch or Stash call. Or, a needed device control entry has been purged. 15 Segment Loader error: A GetResource call to read a segment into memory failed. 16 Floating point error: The halt bit in the floating-point environment word was set. 17-24 Can't load package: A GetResource call to read a package into memory failed. 25 Can't allocate requested memory block in the heap 26 Segment Loader error: A GetResource call to read 'CODE' resource 0 into memory failed; usually indicates a nonexecutable file. 27 File map destroyed: A logical block number was found that's greater than the number of the last logical block on the volume or less than the logical block number of the first allocation block on the volume. 28 Stack overflow error: The stack has expanded into the heap. 30 "Please insert the disk:" File Manager alert 41 The file named "Finder" can't be found on the disk. 100 Can't mount system startup volume. The system couldn't read the system resource file into memory. 32767 "Sorry, a system error occurred": Default alert message æKY Events.p æKL Button EventAvail GetCaretTime GetDblTime GetKeys GetMouse GetNextEvent StillDown TickCount WaitMouseUp WaitNextEvent activateEvt activeFlag activMask adbAddrMask alphaLock app1Evt app1Mask app2Evt app2Mask app3Evt app3Mask app4Evt app4Mask autoKey autoKeyMask btnState charCodeMask childDiedMessage cmdKey controlKey diskEvt diskMask driverEvt driverMask EventRecord everyEvent keyCodeMask keyDown keyDownMask KeyMap keyUp keyUpMask mDownMask mouseDown mouseMovedMessage mouseUp mUpMask networkEvt networkMask nullEvent optionKey osEvt osEvtMessageMask shiftKey suspendResumeMessage updateEvt updateMask æKY nullEvent æFp Events.p æT CONST æD nullEvent = 0; æC »Event Code The what field of an event record contains an event code identifying the type of the event. The event codes are available as predefined constants: CONST nullEvent = 0; {null} mouseDown = 1; {mouse-down} mouseUp = 2; {mouse-up} keyDown = 3; {key-down} keyUp = 4; {key-up} autoKey = 5; {auto-key} updateEvt = 6; {update} diskEvt = 7; {disk-inserted} activateEvt = 8; {activate} networkEvt = 10; {network} driverEvt = 11; {device driver} app1Evt = 12; {application-defined} app2Evt = 13; {application-defined} app3Evt = 14; {application-defined} app4Evt = 15; {application-defined} æKY mouseDown æFp Events.p æT CONST æD mouseDown = 1; æC æKY mouseUp æFp Events.p æT CONST æD mouseUp = 2; æC æKY keyDown æFp Events.p æT CONST æD keyDown = 3; æC æKY keyUp æFp Events.p æT CONST æD keyUp = 4; æC æKY autoKey æFp Events.p æT CONST æD autoKey = 5; æC æKY updateEvt æFp Events.p æT CONST æD updateEvt = 6; æC æKY diskEvt æFp Events.p æT CONST æD diskEvt = 7; æC æKY activateEvt æFp Events.p æT CONST æD activateEvt = 8; æC æKY networkEvt æFp Events.p æT CONST æD networkEvt = 10; æC æKY driverEvt æFp Events.p æT CONST æD driverEvt = 11; æC æKY app1Evt æFp Events.p æT CONST æD app1Evt = 12; æC æKY app2Evt æFp Events.p æT CONST æD app2Evt = 13; æC æKY app3Evt æFp Events.p æT CONST æD app3Evt = 14; æC æKY app4Evt æFp Events.p æT CONST æD app4Evt = 15; æC æKY osEvt æFp Events.p æT CONST æD osEvt = app4Evt; æC æKY charCodeMask æFp Events.p æT CONST æD charCodeMask = $000000FF; æC æKY keyCodeMask æFp Events.p æT CONST æD keyCodeMask = $0000FF00; æC æKY adbAddrMask æFp Events.p æT CONST æD adbAddrMask = $00FF0000; æC æKY osEvtMessageMask æFp Events.p æT CONST æD osEvtMessageMask = $FF000000; æC æKY mouseMovedMessage æFp Events.p æT CONST æD { OSEvent Messages } mouseMovedMessage = $FA; æC æKY childDiedMessage æFp Events.p æT CONST æD childDiedMessage = $FD; æC æKY suspendResumeMessage æFp Events.p æT CONST æD suspendResumeMessage = $01; æC æKY mDownMask æFp Events.p æT CONST æD { event mask equates } mDownMask = 2; æC _______________________________________________________________________________ »EVENT MASKS _______________________________________________________________________________ Some of the Event Manager routines can be restricted to operate on a specific event type or group of types; in other words, the specified event types are enabled while all others are disabled. For instance, instead of just requesting the next available event, you can specifically ask for the next keyboard event. You specify which event types a particular Event Manager call applies to by supplying an event mask as a parameter. This is an integer in which there’s one bit position for each event type, as shown in Figure 8. The bit position representing a given type corresponds to the event code for that type—for example, update events (event code 6) are specified by bit 6 of the mask. A 1 in bit 6 means that this Event Manager call applies to update events; a 0 means that it doesn’t. •••Refer to Figure 8.••• Figure 8–Event Mask Masks for each individual event type are available as predefined constants: CONST mDownMask = 2; {mouse-down} mUpMask = 4; {mouse-up} keyDownMask = 8; {key-down} keyUpMask = 16; {key-up} autoKeyMask = 32; {auto-key} updateMask = 64; {update} diskMask = 128; {disk-inserted} activMask = 256; {activate} networkMask = 1024; {network} driverMask = 2048; {device driver} app1Mask = 4096; {application-defined} app2Mask = 8192; {application-defined} app3Mask = 16384; {application-defined} app4Mask = -32768; {application-defined} Note: Null events can’t be disabled; a null event will always be reported when none of the enabled types of events are available. The following predefined mask designates all event types: CONST everyEvent = -1; {all event types} You can form any mask you need by adding or subtracting these mask constants. For example, to specify every keyboard event, use keyDownMask + keyUpMask + autoKeyMask For every event except an update, use everyEvent - updateMask Note: It’s recommended that you always use the event mask everyEvent unless there’s a specific reason not to. There’s also a global system event mask that controls which event types get posted into the event queue. Only event types corresponding to bits set in the system event mask are posted; all others are ignored. When the system starts up, the system event mask is set to post all except key-up event—that is, it’s initialized to everyEvent - keyUpMask Note: Key-up events are meaningless for most applications. Your application will usually want to ignore them; if not, it can set the system event mask with the Operating System Event Manager procedure SetEventMask. æKY mUpMask æFp Events.p æT CONST æD mUpMask = 4; æC æKY keyDownMask æFp Events.p æT CONST æD keyDownMask = 8; æC æKY keyUpMask æFp Events.p æT CONST æD keyUpMask = 16; æC æKY autoKeyMask æFp Events.p æT CONST æD autoKeyMask = 32; æC æKY updateMask æFp Events.p æT CONST æD updateMask = 64; æC æKY diskMask æFp Events.p æT CONST æD diskMask = 128; æC æKY activMask æFp Events.p æT CONST æD activMask = 256; æC æKY networkMask æFp Events.p æT CONST æD networkMask = 1024; æC æKY driverMask æFp Events.p æT CONST æD driverMask = 2048; æC æKY app1Mask æFp Events.p æT CONST æD app1Mask = 4096; æC æKY app2Mask æFp Events.p æT CONST æD app2Mask = 8192; æC æKY app3Mask æFp Events.p æT CONST æD app3Mask = 16384; æC æKY app4Mask æFp Events.p æT CONST æD app4Mask = -32768; æC æKY everyEvent æFp Events.p æT CONST æD everyEvent = -1; æC æKY activeFlag æFp Events.p æT CONST æD { modifiers } activeFlag = 1; {bit 0 of modifiers for activate event} æC »Modifier Flags As mentioned above, the modifiers field of an event record contains further information about activate events and the state of the modifier keys and mouse button at the time the event was posted (see Figure 7). You might look at this field to find out, for instance, whether the Command key was down when a mouse-down event was posted (which in many applications affects the way objects are selected) or when a key-down event was posted (which could mean the user is choosing a menu item by typing its keyboard equivalent). •••Refer to Figure 7.••• Figure 7–Modifier Flags The following predefined constants are useful as masks for reading the flags in the modifiers field: CONST activeFlag = 1; {set if window being activated} btnState = 128; {set if mouse button up} cmdKey = 256; {set if Command key down} shiftKey = 512; {set if Shift key down} alphaLock = 1024; {set if Caps Lock key down} optionKey = 2048; {set if Option key down} controlKey = 4096; {set if Control key down} The activeFlag bit gives further information about activate events; it’s set if the window pointed to by the event message is being activated, or 0 if the window is being deactivated. The remaining bits indicate the state of the mouse button and modifier keys. Notice that the btnState bit is set if the mouse button is up, whereas the bits for the four modifier keys are set if their corresponding keys are down. æKY btnState æFp Events.p æT CONST æD btnState = 128; {Bit 7 of low byte is mouse button state} æC æKY cmdKey æFp Events.p æT CONST æD cmdKey = 256; {Bit 0} æC æKY shiftKey æFp Events.p æT CONST æD shiftKey = 512; {Bit 1} æC æKY alphaLock æFp Events.p æT CONST æD alphaLock = 1024; {Bit 2 } æC æKY optionKey æFp Events.p æT CONST æD optionKey = 2048; {Bit 3 of high byte} æC æKY controlKey æFp Events.p æT CONST æD controlKey = 4096; æC æKY EventRecord æFp Events.p æT RECORD æD EventRecord = RECORD what: INTEGER; message: LONGINT; when: LONGINT; where: Point; modifiers: INTEGER; END; æC _______________________________________________________________________________ »EVENT RECORDS _______________________________________________________________________________ Every event is represented internally by an event record containing all pertinent information about that event. The event record includes the following information: • the type of event • the time the event was posted (in ticks since system startup) • the location of the mouse at the time the event was posted (in global coordinates) • the state of the mouse button and modifier keys at the time the event was posted • any additional information required for a particular type of event, such as which key the user pressed or which window is being activated Every event has an event record containing this information—even null events. Event records are defined as follows: TYPE EventRecord = RECORD what: INTEGER; {event code} message: LONGINT; {event message} when: LONGINT; {ticks since startup} where: Point; {mouse location} modifiers: INTEGER {modifier flags} END; The when field contains the number of ticks since the system last started up, and the where field gives the location of the mouse, in global coordinates, at the time the event was posted. The other three fields are described below. _______________________________________________________________________________ »Event Code The what field of an event record contains an event code identifying the type of the event. The event codes are available as predefined constants: CONST nullEvent = 0; {null} mouseDown = 1; {mouse-down} mouseUp = 2; {mouse-up} keyDown = 3; {key-down} keyUp = 4; {key-up} autoKey = 5; {auto-key} updateEvt = 6; {update} diskEvt = 7; {disk-inserted} activateEvt = 8; {activate} networkEvt = 10; {network} driverEvt = 11; {device driver} app1Evt = 12; {application-defined} app2Evt = 13; {application-defined} app3Evt = 14; {application-defined} app4Evt = 15; {application-defined} _______________________________________________________________________________ »Event Message The message field of an event record contains the event message, which conveys additional important information about the event. The nature of this information depends on the event type, as summarized in the following table and described below. Event type Event message Keyboard Character code, key code, and ADB address field Activate, update Pointer to window Disk-inserted Drive number in low-order word, File Manager result code in high-order word Mouse-down, Undefined mouse-up, null Network Handle to parameter block Device driver See chapter describing driver Application-defined Whatever you wish For keyboard events, the low-order byte of the low-order word of the event message contains the ASCII character code generated by the key or combination of keys that was pressed or released; usually this is all you’ll need. However, as described in the Apple Desktop Bus chapter, the Macintosh II and SE can be connected to multiple keyboards. To identify the origin of keyboard events, the keyboard event message contains a new ADB address field. It now has the structure shown in Figure 2. Warning: The high byte of the event message for keyboard events is reserved for future use, and is not presently guaranteed to be zero. The event message for non-keyboard events remains the same as described above. •••Refer to Figure 2.••• Figure 2–Event Message for Keyboard Events The key code in the event message for a keyboard event represents the character key that was pressed or released; this value is always the same for any given character key, regardless of the modifier keys pressed along with it. Key codes are useful in special cases—in a music generator, for example—where you want to treat the keyboard as a set of keys unrelated to characters. Figure 3 gives the key codes for all the keys on the keyboard and keypad. (Key codes are shown for modifier keys here because they’re meaningful in other contexts, as explained later.) Both the U.S. and international keyboards are shown; in some cases the codes are quite different (for example, space and Enter are reversed). Three keyboards are now available as standard equipment with Macintosh computers sold in the U.S. They are • The Macintosh Plus Keyboard, which includes cursor control keys and an integral keypad. Its layout and key coding is shown in Figure 4. • The Macintosh II Keyboard, also shipped with the Macintosh SE, which adds Esc (Escape) and Control keys and is connected to the Apple Desktop Bus. Its layout and key coding is shown in Figure 5. • The Apple Extended Keyboard, which the user may connect to the Apple Desktop Bus of any Macintosh II or Macintosh SE computer. Its layout and key coding is shown in Figure 6. These figures show the virtual key codes for each key; they are the key codes that actually appear in keyboard events. In the case of the Macintosh II and Apple Extended Keyboards, however, the hardware produces raw key codes, which may be different. Raw key codes are translated to virtual key codes by the 'KMAP' resource in the System Folder. By modifying the 'KMAP' resource you can change the key codes for any keys. Similarly, you can change the ASCII codes corresponding to specific key codes by modifying the 'KCHR' resource in the System Folder. The 'KMAP' and 'KCHR' resources are described in the Resource Manager chapter. With both the Macintosh II and the Apple Extended keyboards, the standard 'KMAP' resource supplied in the system folder reassigns the following raw key codes to different virtual key codes: Key Raw key code Virtual key code Control 36 3B Left cursor 3B 7B Right cursor 3C 7C Down cursor 3D 7D Up cursor 3E 7E The standard 'KMAP' resource leaves all other raw key codes and virtual key codes the same. With the Apple Extended Keyboard, the virtual key codes for three more keys may be easily reassigned, as described above under “Reassigning Right Key Codes”. The following predefined constants are available to help you access the character code and key code: CONST charCodeMask = $000000FF; {character code} keyCodeMask = $0000FF00; {key code} •••Refer to Figure 3.••• Figure 3–Key Codes •••Refer to Figure 4.••• Figure 4–Macintosh Plus Keyboard •••Refer to Figure 5.••• Figure 5–Macintosh II Keyboard •••Refer to Figure 6.••• Figure 6–Apple Extended Keyboard Note: You can use the Toolbox Utility function BitAnd with these constants; for instance, to access the character code, use charCode := BitAnd(my Event.message,charCodeMask) _______________________________________________________________________________ THE TOOLBOX EVENT MANAGER _______________________________________________________________________________ For activate and update events, the event message is a pointer to the window affected. (If the event is an activate event, additional important information about the event can be found in the modifiers field of the event record, as described below.) For disk-inserted events, the low-order word of the event message contains the drive number of the disk drive into which the disk was inserted: 1 for the Macintosh’s built-in drive, and 2 for the external drive, if any. Numbers greater than 2 denote additional disk drives connected to the Macintosh. By the time your application receives a disk-inserted event, the system will already have attempted to mount the volume on the disk by calling the File Manager function MountVol; the high-order word of the event message will contain the result code returned by MountVol. For mouse-down, mouse-up, and null events, the event message is undefined and should be ignored. The event message for a network event contains a handle to a parameter block, as described in the AppleTalk Manager chapter. For device driver events, the contents of the event message depend on the situation under which the event was generated; the chapters describing those situations will give the details. Finally, you can use the event message however you wish for application-defined event types. _______________________________________________________________________________ »Modifier Flags As mentioned above, the modifiers field of an event record contains further information about activate events and the state of the modifier keys and mouse button at the time the event was posted (see Figure 7). You might look at this field to find out, for instance, whether the Command key was down when a mouse-down event was posted (which in many applications affects the way objects are selected) or when a key-down event was posted (which could mean the user is choosing a menu item by typing its keyboard equivalent). •••Refer to Figure 7.••• Figure 7–Modifier Flags The following predefined constants are useful as masks for reading the flags in the modifiers field: CONST activeFlag = 1; {set if window being activated} btnState = 128; {set if mouse button up} cmdKey = 256; {set if Command key down} shiftKey = 512; {set if Shift key down} alphaLock = 1024; {set if Caps Lock key down} optionKey = 2048; {set if Option key down} controlKey = 4096; {set if Control key down} The activeFlag bit gives further information about activate events; it’s set if the window pointed to by the event message is being activated, or 0 if the window is being deactivated. The remaining bits indicate the state of the mouse button and modifier keys. Notice that the btnState bit is set if the mouse button is up, whereas the bits for the four modifier keys are set if their corresponding keys are down. æKY KeyMap æFp Events.p æT RECORD æD KeyMap = PACKED ARRAY [0..127] OF BOOLEAN; æC æKY GetNextEvent æFp Events.p æT FUNCTION æTN A970 æD FUNCTION GetNextEvent(eventMask: INTEGER;VAR theEvent: EventRecord): BOOLEAN; INLINE $A970; æDT myVariable := GetNextEvent(eventMask,theEvent); æMM æRT 3, 5, 85, 194, 205 æRI I-257, N3-1, N5-1, N85, P-30, 32, 34, 39, 40, 97, 108, 173 æC GetNextEvent returns the next available event of a specified type or types and, if the event is in the event queue, removes it from the queue. The event is returned in the parameter theEvent. The eventMask parameter specifies which event types are of interest. GetNextEvent returns the next available event of any type designated by the mask, subject to the priority rules discussed above under “Priority of Events”. If no event of any of the designated types is available, GetNextEvent returns a null event. Note: Events in the queue that aren’t designated in the mask are kept in the queue; if you want to remove them, you can do so by calling the Operating System Event Manager procedure FlushEvents. Before reporting an event to your application, GetNextEvent first calls the Desk Manager function SystemEvent to see whether the system wants to intercept and respond to the event. If so, or if the event being reported is a null event, GetNextEvent returns a function result of FALSE; a function result of TRUE means that your application should handle the event itself. The Desk Manager intercepts the following events: • activate and update events directed to a desk accessory • mouse-up and keyboard events, if the currently active window belongs to a desk accessory Note: In each case, the event is intercepted by the Desk Manager only if the desk accessory can handle that type of event; however, as a rule all desk accessories should be set up to handle activate, update, and keyboard events and should not handle mouse-up events. The Desk Manager also intercepts disk-inserted events: It attempts to mount the volume on the disk by calling the File Manager function MountVol. GetNextEvent will always return TRUE in this case, though, so that your application can take any further appropriate action after examining the result code returned by MountVol in the event message. (See the Desk Manager and File Manager chapters.) GetNextEvent returns TRUE for all other non-null events (including all mouse-down events, regardless of which window is active), leaving them for your application to handle. GetNextEvent also makes the following processing happen, invisible to your program: • If the “alarm” is set and the current time is the alarm time, the alarm goes off (a beep followed by blinking the apple symbol in the menu bar). The user can set the alarm with the Alarm Clock desk accessory. • If the user holds down the Command and Shift keys while pressing a numeric key that has a special effect, that effect occurs. The standard such keys are 1 and 2 for ejecting the disk in the internal or external drive, and 3 and 4 for writing a snapshot of the screen to a MacPaint document or to the printer. Note: Advanced programmers can implement their own code to be executed in response to Command-Shift-number combinations (except for Command- Shift-1 and 2, which can’t be changed). The code corresponding to a particular number must be a routine having no parameters, stored in a resource whose type is 'FKEY' and whose ID is the number. The system resource file contains code for the numbers 3 and 4. Assembly-language note: You can disable GetNextEvent’s processing of Command- Shift-number combinations by setting the global variable ScrDmpEnb (a byte) to 0. æKY WaitNextEvent æFp Events.p æT FUNCTION æTN A860 æD FUNCTION WaitNextEvent(mask: INTEGER;VAR event: EventRecord;sleep: LONGINT; mouseRgn: RgnHandle): BOOLEAN; INLINE $A860; æDT myVariable := WaitNextEvent(mask,event,sleep,mouseRgn); æRT 158, 177, 180, 194, 205 æRI N158-1 æC æKY EventAvail æFp Events.p æT FUNCTION æTN A971 æD FUNCTION EventAvail(eventMask: INTEGER;VAR theEvent: EventRecord): BOOLEAN; INLINE $A971; æDT myVariable := EventAvail(eventMask,theEvent); æMM æRT 194 æRI I-259 æC EventAvail works exactly the same as GetNextEvent except that if the event is in the event queue, it’s left there. Note: An event returned by EventAvail will not be accessible later if in the meantime the queue becomes full and the event is discarded from it; since the events discarded are always the oldest ones in the queue, however, this will happen only in an unusually busy environment. æKY GetMouse æFp Events.p æT PROCEDURE æTN A972 æD PROCEDURE GetMouse(VAR mouseLoc: Point); INLINE $A972; æDT GetMouse(mouseLoc); æMM æRI I-259 æC GetMouse returns the current mouse location in the mouseLoc parameter. The location is given in the local coordinate system of the current grafPort (which might be, for example, the currently active window). Notice that this differs from the mouse location stored in the where field of an event record; that location is always in global coordinates. æKY Button æFp Events.p æT FUNCTION æTN A974 æD FUNCTION Button: BOOLEAN; INLINE $A974; æDT myVariable := Button(paramList); æMM æRI I-259 æC The Button function returns TRUE if the mouse button is currently down, and FALSE if it isn’t. æKY StillDown æFp Events.p æT FUNCTION æTN A973 æD FUNCTION StillDown: BOOLEAN; INLINE $A973; æDT myVariable := StillDown(paramList); æMM æRT 194 æRI I-259 æC Usually called after a mouse-down event, StillDown tests whether the mouse button is still down. It returns TRUE if the button is currently down and there are no more mouse events pending in the event queue. This is a true test of whether the button is still down from the original press—unlike Button (above), which returns TRUE whenever the button is currently down, even if it has been released and pressed again since the original mouse-down event. æKY WaitMouseUp æFp Events.p æT FUNCTION æTN A977 æD FUNCTION WaitMouseUp: BOOLEAN; INLINE $A977; æDT myVariable := WaitMouseUp(paramList); æMM æRT 194 æRI I-259 æC WaitMouseUp works exactly the same as StillDown (above), except that if the button is not still down from the original press, WaitMouseUp removes the preceding mouse-up event before returning FALSE. If, for instance, your application attaches some special significance both to mouse double-clicks and to mouse-up events, this function would allow your application to recognize a double-click without being confused by the intervening mouse-up. æKY GetKeys æFp Events.p æT PROCEDURE æTN A976 æD PROCEDURE GetKeys(VAR theKeys: KeyMap); INLINE $A976; { PROCEDUREGetKeys (VAR theKeys: KeyMap); GetKeys reads the current state of the keyboard (and keypad, if any) and returns it in the form of a keyMap: TYPE KeyMap = PACKED ARRAY [Ø..127] OF BOOLEAN; Each key on the keyboard or keypad corresponds to an element in the keyMap. The index into the keyMap for a particular key is the same as the key code for that key. (The key codes are shown in Figure 3 above.) The keyMap element is TRUE if the corresponding key is down and FALSE if it isn't. The maximum number of keys that can be down simultaneously is two character keys plus any combination of the four modifier keys. } æDT GetKeys(theKeys); æMM æRI I-259 æC GetKeys reads the current state of the keyboard (and keypad, if any) and returns it in the form of a keyMap: TYPE KeyMap = PACKED ARRAY[0..127] OF BOOLEAN; Each key on the keyboard or keypad corresponds to an element in the keyMap. The index into the keyMap for a particular key is the same as the key code for that key. (The key codes are shown in Figure 3 above.) The keyMap element is TRUE if the corresponding key is down and FALSE if it isn’t. The maximum number of keys that can be down simultaneously is two character keys plus any combination of the four modifier keys. æKY TickCount æFp Events.p æT FUNCTION æTN A975 æD FUNCTION TickCount: LONGINT; INLINE $A975; æDT myVariable := TickCount(paramList); æMM æRI I-260 æC TickCount returns the current number of ticks (sixtieths of a second) since the system last started up. Warning: Don’t rely on the tick count being exact; it will usually be accurate to within one tick, but may be off by more than that. The tick count is incremented during the vertical retrace interrupt, but it’s possible for this interrupt to be disabled. Furthermore, don’t rely on the tick count being incremented to a certain value, such as testing whether it has become equal to its old value plus 1; check instead for “greater than or equal to” (since an interrupt task may keep control for more than one tick). Assembly-language note: The value returned by this function is also contained in the global variable Ticks. æKY GetDblTime æFp Events.p æT FUNCTION æD FUNCTION GetDblTime: LONGINT; INLINE $2EB8,$02F0; æDT myVariable := GetDblTime(paramList); æRI I-260 æC [Not in ROM] GetDblTime returns the suggested maximum difference (in ticks) that should exist between the times of a mouse-up event and a mouse-down event for those two mouse clicks to be considered a double-click. The user can adjust this value by means of the Control Panel desk accessory. Assembly-language note: This value is available to assembly-language programmers in the global variable DoubleTime. æKY GetCaretTime æFp Events.p æT FUNCTION æD FUNCTION GetCaretTime: LONGINT; INLINE $2EB8,$02F4; æDT myVariable := GetCaretTime(paramList); æRI I-260 æC [Not in ROM] GetCaretTime returns the time (in ticks) between blinks of the “caret” (usually a vertical bar) marking the insertion point in editable text. If you aren’t using TextEdit, you’ll need to cause the caret to blink yourself; on every pass through your program’s main event loop, you should check this value against the elapsed time since the last blink of the caret. The user can adjust this value by means of the Control Panel desk accessory. Assembly-language note: This value is available to assembly-language programmers in the global variable CaretTime. æKY Files.p æKL AddDrive Allocate AllocContig CatMove CloseWD Create DirCreate Eject FInitQueue FlushVol FSClose FSDelete FSOpen FSpCatMove FSpCreate FSpCreateResFile FSpDelete FSpDirCreate FSpGetFInfo FSpOpenDF FSpOpenResFile FSpOpenRF FSpRename FSpRstFLock FSpSetFInfo FSpSetFLock FSRead FSWrite GetDrvQHdr GetEOF GetFInfo GetFPos GetFSQHdr GetVCBQHdr GetVInfo GetVol GetVRefNum GetWDInfo HCreate HDelete HGetFInfo HGetVol HOpen HOpenRF HRename HRstFLock HSetFInfo HSetFLock HSetVol MakeFSSpec OpenRF OpenWD PBAllocate PBAllocContig PBCatMove PBClose PBCloseWD PBCreate PBCreateFileID PBDelete PBDeleteFileID PBDirCreate PBDTAddAPPL PBDTAddIcon PBDTCloseDown PBDTDelete PBDTFlush PBDTGetAPPL PBDTGetComment PBDTGetIcon PBDTGetIconInfo PBDTGetInfo PBDTGetPath PBDTOpenInform PBDTRemoveAPPL PBDTRemoveComment PBDTReset PBDTSetComment PBEject PBExchangeFiles PBFlushFile PBFlushVol PBGetAltAccess PBGetCatInfo PBGetEOF PBGetFCBInfo PBGetFInfo PBGetFPos PBGetVInfo PBGetVol PBGetWDInfo PBHCopyFile PBHCreate PBHDelete PBHGetDirAccess PBHGetFInfo PBHGetLogInInfo PBHGetVInfo PBHGetVol PBHGetVolParms PBHMapID PBHMapName PBHMoveRename PBHOpen PBHOpenDeny PBHOpenDF PBHOpenRF PBHOpenRFDeny PBHRename PBHRstFLock PBHSetDirAccess PBHSetFInfo PBHSetFLock PBHSetVol PBLockRange PBMakeFSSpec PBMountVol PBOffLine PBOpen PBOpenDF PBOpenRF PBOpenWD PBRead PBRename PBResolveFileID PBRstFLock PBSetAltAccess PBSetCatInfo PBSetEOF PBSetFInfo PBSetFLock PBSetFPos PBSetFVers PBSetVInfo PBSetVol PBUnlockRange PBUnmountVol PBWrite Rename RstFLock SetEOF SetFInfo SetFLock SetFPos SetVol UnmountVol alphaStage betaStage CatPositionRec CInfoPBPtr CInfoPBRec CInfoType CMovePBPtr CMovePBRec developStage DInfo dirInfo DTPBPtr DTPBRec DXInfo FCBPBPtr FCBPBRec fDesktop fDisk fHasBundle finalStage fInvisible fOnDesk fsAtMark fsCurPerm fsFromLEOF fsFromMark fsFromStart fsRdPerm fsRdWrPerm fsRdWrShPerm fsRtDirID fsRtParID fsSBDrBkDat fsSBDrCrDat fsSBDrFndrInfo fsSBDrMdDat fsSBDrNmFls fsSBDrParID fsSBDrUsrWds fsSBFlAttrib fsSBFlBkDat fsSBFlCrDat fsSBFlFndrInfo fsSBFlLgLen fsSBFlMdDat fsSBFlParID fsSBFlPyLen fsSBFlRLgLen fsSBFlRPyLen fsSBFlXFndrInfo fsSBFullName fsSBNegate fsSBPartialName FSSpec FSSpecArray FSSpecArrayHandle FSSpecArrayPtr fsWrPerm fTrash FXInfo hFileInfo HParamBlockRec HParmBlkPtr ioDirFlg ioDirMask NumVersion rdVerify VersRec VersRecHndl VersRecPtr WDPBPtr WDPBRec æKY fsAtMark æFp Files.p æT CONST æD { Finder Constants } fsAtMark = 0; æC If you specify fsAtMark, ioPosOffset is ignored and the operation begins wherever the mark is currently positioned. If you choose to set the mark (relative to either the beginning of the file, the logical end-of-file, or the current mark), ioPosOffset must specify the byte offset from the chosen point (either positive or negative) where the operation should begin. Note: Advanced programmers: Bit 7 of ioPosMode is the newline flag; it’s set if read operations should terminate at a newline character. The ASCII code of the newline character is specified in the high-order byte of ioPosMode. If the newline flag is set, the data will be read one byte at a time until the newline character is encountered, ioReqCount bytes have been read, or the end-of-file is reached. If the newline flag is clear, the data will be read one byte at a time until ioReqCount bytes have been read or the end-of-file is reached. æKY fOnDesk æFp Files.p æT CONST æD fOnDesk = 1; æC æKY fsCurPerm æFp Files.p æT CONST æD fsCurPerm = 0; æC This request is compared with the open permission of the file. If the open permission doesn’t allow I/O as requested, a result code indicating the error is returned. Warning: To ensure data integrity be sure to lock the portion of the file you’ll be using if you specify shared write permission. æKY fHasBundle æFp Files.p æT CONST æD fHasBundle = 8192; æC æKY fsRdPerm æFp Files.p æT CONST æD fsRdPerm = 1; æC æKY fInvisible æFp Files.p æT CONST æD fInvisible = 16384; æC æKY fTrash æFp Files.p æT CONST æD fTrash = -3; æC æKY fsWrPerm æFp Files.p æT CONST æD fsWrPerm = 2; æC æKY fDesktop æFp Files.p æT CONST æD fDesktop = -2; æC æKY fsRdWrPerm æFp Files.p æT CONST æD fsRdWrPerm = 3; æC æKY fDisk æFp Files.p æT CONST æD fDisk = 0; æC æKY fsRdWrShPerm æFp Files.p æT CONST æD fsRdWrShPerm = 4; æC æKY fsFromStart æFp Files.p æT CONST æD fsFromStart = 1; æC æKY fsFromLEOF æFp Files.p æT CONST æD fsFromLEOF = 2; æC æKY fsFromMark æFp Files.p æT CONST æD fsFromMark = 3; æC æKY rdVerify æFp Files.p æT CONST æD rdVerify = 64; æC To have the File Manager verify that all data written to a volume exactly matches the data in memory, make a Read call right after the Write call. The parameters for a read-verify operation are the same as for a standard Read call, except that the following constant must be added to the positioning mode: CONST rdVerify = 64; {read-verify mode} The result code ioErr is returned if any of the data doesn’t match. æKY ioDirFlg æFp Files.p æT CONST æD ioDirFlg = 3; æC æKY ioDirMask æFp Files.p æT CONST æD ioDirMask = $10; æC æKY fsRtParID æFp Files.p æT CONST æD fsRtParID = 1; æC æKY fsRtDirID æFp Files.p æT CONST æD fsRtDirID = 2; æC æKY fsSBNegate æFp Files.p æT CONST æD fsSBNegate = 16384; æC æKY fsSBPartialName æFp Files.p æT CONST æD { masks for SpecBits values } fsSBPartialName = 1; æC æKY fsSBFullName æFp Files.p æT CONST æD fsSBFullName = 2; æC æKY fsSBFlAttrib æFp Files.p æT CONST æD fsSBFlAttrib = 4; æC æKY fsSBFlFndrInfo æFp Files.p æT CONST æD fsSBFlFndrInfo = 8; æC æKY fsSBFlLgLen æFp Files.p æT CONST æD fsSBFlLgLen = 32; æC æKY fsSBFlPyLen æFp Files.p æT CONST æD fsSBFlPyLen = 64; æC æKY fsSBFlRLgLen æFp Files.p æT CONST æD fsSBFlRLgLen = 128; æC æKY fsSBFlRPyLen æFp Files.p æT CONST æD fsSBFlRPyLen = 256; æC æKY fsSBFlCrDat æFp Files.p æT CONST æD fsSBFlCrDat = 512; æC æKY fsSBFlMdDat æFp Files.p æT CONST æD fsSBFlMdDat = 1024; æC æKY fsSBFlBkDat æFp Files.p æT CONST æD fsSBFlBkDat = 2048; æC æKY fsSBFlXFndrInfo æFp Files.p æT CONST æD fsSBFlXFndrInfo = 4096; æC æKY fsSBFlParID æFp Files.p æT CONST æD fsSBFlParID = 8192; æC æKY fsSBDrUsrWds æFp Files.p æT CONST æD fsSBDrUsrWds = 8; æC æKY fsSBDrNmFls æFp Files.p æT CONST æD fsSBDrNmFls = 16; æC æKY fsSBDrCrDat æFp Files.p æT CONST æD fsSBDrCrDat = 512; æC æKY fsSBDrMdDat æFp Files.p æT CONST æD fsSBDrMdDat = 1024; æC æKY fsSBDrBkDat æFp Files.p æT CONST æD fsSBDrBkDat = 2048; æC æKY fsSBDrFndrInfo æFp Files.p æT CONST æD fsSBDrFndrInfo = 4096; æC æKY fsSBDrParID æFp Files.p æT CONST æD fsSBDrParID = 8192; æC æKY developStage æFp Files.p æT CONST æD { Version Release Stage Codes } developStage = $20; æC æKY alphaStage æFp Files.p æT CONST æD alphaStage = $40; æC æKY betaStage æFp Files.p æT CONST æD betaStage = $60; æC æKY finalStage æFp Files.p æT CONST æD finalStage = $80; æC æKY CInfoType hFileInfo dirInfo æFp Files.p æT TYPE æD CInfoType = (hFileInfo,dirInfo); æC æKY FXInfo æFp Files.p æT RECORD æD FXInfo = RECORD fdIconID: INTEGER; {Icon ID} fdUnused: ARRAY [1..4] OF INTEGER; {unused but reserved 8 bytes} fdComment: INTEGER; {Comment ID} fdPutAway: LONGINT; {Home Dir ID} END; æC On hierarchical volumes, in addition to the FInfo record, the following information about files is maintained for the Finder: æKY DInfo æFp Files.p æT RECORD æD DInfo = RECORD frRect: Rect; {folder rect} frFlags: INTEGER; {Flags} frLocation: Point; {folder location} frView: INTEGER; {folder view} END; æC On hierarchical volumes, the following information about directories is maintained for the Finder: DInfo = RECORD frRect: Rect; {folder's rectangle} frFlags: INTEGER; {flags} frLocation: Point; {folder's location} frView: INTEGER; {folder's view} END; DXInfo = RECORD frScroll: Point; {scroll position} frOpenChain: LONGINT; {directory ID chain of open folders} frUnused: INTEGER; {reserved} frComment: INTEGER; {comment ID} frPutAway: LONGINT; {directory ID} END; When a file (or folder) is moved to the desktop on a hierarchical volume, it’s actually moved to the root level of the file directory. (This permits all the desktop icons to be enumerated by one simple scan of the root.) The fOnDesk bit of fdFlags is set. FDPutAway (or frPutAway for directories) contains the directory ID of the folder that originally contained the file (or folder); this allows the file (or folder) to be returned there from the desktop. æKY DXInfo æFp Files.p æT RECORD æD DXInfo = RECORD frScroll: Point; {scroll position} frOpenChain: LONGINT; {DirID chain of open folders} frUnused: INTEGER; {unused but reserved} frComment: INTEGER; {comment} frPutAway: LONGINT; {DirID} END; æC æKY CMovePBRec CMovePBPtr æFp Files.p æT RECORD æD CMovePBPtr = ^CMovePBRec; CMovePBRec = RECORD qLink: QElemPtr; qType: INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion: ProcPtr; ioResult: OSErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; filler1: LONGINT; ioNewName: StringPtr; filler2: LONGINT; ioNewDirID: LONGINT; filler3: ARRAY [1..2] OF LONGINT; ioDirID: LONGINT; END; æC »CMovePBRec When you call CatMove to move files or directories into a different directory, you’ll use the following six additional fields after the standard eight fields in the parameter block record CMovePBRec: filler1: LONGINT; {not used} ioNewName: StringPtr; {name of new directory} filler2: LONGINT; {not used} ioNewDirID: LONGINT; {directory ID of new directory} filler3: ARRAY[1..2] OF LONGINT; {not used} ioDirID: LONGINT); {directory ID of current directory} IONewName and ioNewDirID specify the name and directory ID of the directory to which the file or directory is to be moved. IODirID (used in conjuntion with the ioVRefNum and ioNamePtr) specifies the current directory ID of the file or directory to be moved. æKY WDPBRec WDPBPtr æFp Files.p æT RECORD æD WDPBPtr = ^WDPBRec; WDPBRec = RECORD qLink: QElemPtr; qType: INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion: ProcPtr; ioResult: OSErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; filler1: INTEGER; ioWDIndex: INTEGER; ioWDProcID: LONGINT; ioWDVRefNum: INTEGER; filler2: ARRAY [1..7] OF INTEGER; ioWDDirID: LONGINT; END; æC »WDPBRec When you call the routines that open, close, and get information about working directories, you’ll use the following six additional fields after the standard eight fields in the parameter block record WDPBRec: filler1: INTEGER; {not used} ioWDIndex: INTEGER; {index} ioWDProcID: LONGINT; {working directory user identifier} ioWDVRefNum: INTEGER; {working directory's volume reference number} filler2: ARRAY[1..7] OF INTEGER; {not used} ioWDDirID: LONGINT); {working directory's directory ID} IOWDIndex can be used with the function PBGetWDInfo to index through the current working directories. IOWDProcID is an identifier that’s used to distinguish between working directories set up by different users; you should use the application’s signature (discussed in the Finder Interface chapter) as the ioWDProcID. æKY FCBPBRec FCBPBPtr æFp Files.p æT RECORD æD FCBPBPtr = ^FCBPBRec; FCBPBRec = RECORD qLink: QElemPtr; qType: INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion: ProcPtr; ioResult: OSErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; ioRefNum: INTEGER; filler: INTEGER; ioFCBIndx: INTEGER; filler1: INTEGER; ioFCBFlNm: LONGINT; ioFCBFlags: INTEGER; ioFCBStBlk: INTEGER; ioFCBEOF: LONGINT; ioFCBPLen: LONGINT; ioFCBCrPs: LONGINT; ioFCBVRefNum: INTEGER; ioFCBClpSiz: LONGINT; ioFCBParID: LONGINT; END; æC æKY CInfoPBRec CInfoPBPtr æFp Files.p æT RECORD æD CInfoPBPtr = ^CInfoPBRec; CInfoPBRec = RECORD qLink: QElemPtr; qType: INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion: ProcPtr; ioResult: OSErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; ioFRefNum: INTEGER; ioFVersNum: SignedByte; filler1: SignedByte; ioFDirIndex: INTEGER; ioFlAttrib: SignedByte; filler2: SignedByte; CASE CInfoType OF hFileInfo: (ioFlFndrInfo: FInfo; ioDirID: LONGINT; ioFlStBlk: INTEGER; ioFlLgLen: LONGINT; ioFlPyLen: LONGINT; ioFlRStBlk: INTEGER; ioFlRLgLen: LONGINT; ioFlRPyLen: LONGINT; ioFlCrDat: LONGINT; ioFlMdDat: LONGINT; ioFlBkDat: LONGINT; ioFlXFndrInfo: FXInfo; ioFlParID: LONGINT; ioFlClpSiz: LONGINT); dirInfo: (ioDrUsrWds: DInfo; ioDrDirID: LONGINT; ioDrNmFls: INTEGER; filler3: ARRAY [1..9] OF INTEGER; ioDrCrDat: LONGINT; ioDrMdDat: LONGINT; ioDrBkDat: LONGINT; ioDrFndrInfo: DXInfo; ioDrParID: LONGINT); END; æC »CInfoPBRec The routines GetCatInfo and SetCatInfo are used for getting and setting information about the files and directories within a directory. With files, you’ll use the following 19 additional fields after the standard eight fields in the parameter block record CInfoPBRec: ioFRefNum: INTEGER; {path reference number} ioFVersNum: SignedByte; {version number} filler1: SignedByte; {not used} ioFDirIndex: INTEGER; {index} ioFlAttrib: SignedByte; {file attributes} filler2: SignedByte; {not used} hFileInfo: (ioFlFndrInfo: FInfo; {information used by the Finder} ioDirID: LONGINT; {directory ID or file number} ioFlStBlk: INTEGER; {first allocation block of data fork} ioFlLgLen: LONGINT; {logical end-of-file of data fork} ioFlPyLen: LONGINT; {physical end-of-file of data fork} ioFlRStBlk: INTEGER; {first allocation block of resource fork} ioFlRLgLen: LONGINT; {logical end-of-file of resource fork} ioFlRPyLen: LONGINT; {physical end-of-file of resource fork} ioFlCrDat: LONGINT; {date and time of creation} ioFlMdDat: LONGINT; {date and time of last modification} ioFlBkDat: LONGINT; {date and time of last backup} ioFlXFndrInfo: FXInfo; {additional information used by the Finder} ioFlParID: LONGINT; {file's parent directory ID (integer)} ioFlClpSiz: LONGINT); {file's clump size} •••Refer to Technical Note #69:••• IOFDirIndex can be used with the function PBGetCatInfo to index through the files and directories in a given directory. For each iteration of the function, you can determine whether it’s a file or a directory by testing bit 4 (the fifth least significant bit) of ioFlAttrib. You can test for a directory by using the Toolbox Utilities BitTst function in the following manner (remember, the Toolbox Utilities routines reverse the standard 68000 notation): BitTst(@myCInfoRec.ioFlAttrib,3) IOFlAttrib contains the following attributes: Bit Meaning 0 Set if file is locked 2 Set if resource fork is open 3 Set if data fork is open 4 Set if a directory 7 Set if file (either fork) is open When passed to a routine, ioDirID contains a directory ID; it can be used to refer to a directory or, in conjuction with a partial pathname from that directory, to other files and directories. If both a directory ID and a working directory reference number are provided, the directory ID is used to identify the directory on the volume indicated by the working directory reference number. In other words, a directory ID specified by the caller will override the working directory referred to by the working directory reference number. If you don’t want this to happen, you can set ioDirID to 0. (If no directory is specified through a working directory reference number, the root directory ID will be used.) Warning: With files, ioDirID returns the file number of the file; when indexing with GetCatInfo, you’ll need to reset this field for each iteration. IOFlStBlk and ioFlRStBlk contain 0 if the file’s data or resource fork is empty, respectively; they’re used only with flat volumes. The date and time in the ioFlCrDat, ioFlMdDat, and ioFlBkDat fields are specified in seconds since midnight, January 1, 1904. IOFlParID contains the directory ID of the file’s parent. IOFlClpSiz is the clump size to be used when writing the file; if it’s 0, the volume’s clump size is used when the file is opened. With directories, you’ll use the following 14 additional fields after the standard eight fields in the parameter block record CInfoPBRec: ioFRefNum: INTEGER; {file reference number} ioFVersNum SignedByte; {version number} filler1: SignedByte; {not used} ioFDirIndex: INTEGER; {index} ioFlAttrib: SignedByte; {file attributes} filler2: SignedByte; {not used} dirInfo: (ioDrUsrWds: DInfo; {information used by the Finder} ioDrDirID: LONGINT; {directory ID} ioDrNmFls: INTEGER; {number of files in directory} filler3: ARRAY[1..9] OF INTEGER; {not used} ioDrCrDat: LONGINT; {date and time of creation} ioDrMdDat: LONGINT; {date and time of last modification} ioDrBkDat: LONGINT; {date and time of last backup} ioDrFndrInfo: DXInfo; {additional information used by the Finder} ioDrParID: LONGINT); {directory's parent directory ID (integer)} IOFDirIndex can be used with the function PBGetCatInfo to index through the files and directories in a given directory. For each iteration of the function, you can determine whether it’s a file or a directory by testing bit 4 of ioFlAttrib. When passed to a routine, ioDrDirID contains a directory ID; it can be used to refer to a directory or, in conjuction with a partial pathname from that directory, to other files and directories. If both a directory ID and a working directory reference number are provided, the directory ID is used to identify the directory on the volume indicated by the working directory reference number. In other words, a directory ID specified by the caller will override the working directory referred to by the working directory reference number. If you don’t want this to happen, you can set ioDirID to 0. (If no directory is specified through a working directory reference number, the root directory ID will be used.) With directories, ioDrDirID returns the directory ID of the directory. IODrNmFls is the number of files and directories contained in this directory (the valence of the directory). The date and time in the ioDrCrDat, ioDrMdDat, and ioDrBkDat fields are specified in seconds since midnight, January 1, 1904. IODrParID contains the directory ID of the directory’s parent. æKY DTPBRec DTPBPtr æFp Files.p æT RECORD æD DTPBPtr = ^DTPBRec; DTPBRec = RECORD qLink: QElemPtr; qType: INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion: ProcPtr; ioResult: OSErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; ioDTRefNum: INTEGER; ioIndex: INTEGER; ioTagInfo: LONGINT; ioDTBuffer: Ptr; ioDTReqCount: LONGINT; ioDTActCount: LONGINT; filler1: SignedByte; ioIconType: SignedByte; filler2: INTEGER; ioDirID: LONGINT; ioFileCreator: OSType; ioFileType: OSType; ioFiller3: LONGINT; ioDTLgLen: LONGINT; ioDTPyLen: LONGINT; ioFiller4: ARRAY [1..14] OF INTEGER; ioAPPLParID: LONGINT; END; æC æKY CatPositionRec æFp Files.p æT RECORD æD CatPositionRec = RECORD initialize: LONGINT; priv: ARRAY [1..6] OF Integer; END; æC æKY FSSpec æFp Files.p æT RECORD æD FSSpec = RECORD vRefNum: Integer; parID: LONGINT; name: Str63; END; æC æKY FSSpecArray FSSpecArrayPtr FSSpecArrayHandle æFp Files.p æT RECORD æD FSSpecArrayPtr = ^FSSpecArray; FSSpecArrayHandle = ^FSSpecArrayPtr; FSSpecArray = ARRAY [0..0] of FSSpec; æC æKY HParamBlockRec HParmBlkPtr æFp Files.p æT RECORD æD HParmBlkPtr = ^HParamBlockRec; HParamBlockRec = RECORD qLink: QElemPtr; qType: INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion: ProcPtr; ioResult: OSErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; CASE ParamBlkType OF IOParam: (ioRefNum: INTEGER; ioVersNum: SignedByte; ioPermssn: SignedByte; ioMisc: Ptr; ioBuffer: Ptr; ioReqCount: LONGINT; {size of buffer area} ioActCount: LONGINT; {length of vol parms data} ioPosMode: INTEGER; ioPosOffset: LONGINT); FileParam: (ioFRefNum: INTEGER; ioFVersNum: SignedByte; filler1: SignedByte; ioFDirIndex: INTEGER; ioFlAttrib: SignedByte; ioFlVersNum: SignedByte; ioFlFndrInfo: FInfo; ioDirID: LONGINT; ioFlStBlk: INTEGER; ioFlLgLen: LONGINT; ioFlPyLen: LONGINT; ioFlRStBlk: INTEGER; ioFlRLgLen: LONGINT; ioFlRPyLen: LONGINT; ioFlCrDat: LONGINT; ioFlMdDat: LONGINT); VolumeParam: (filler2: LONGINT; ioVolIndex: INTEGER; ioVCrDate: LONGINT; ioVLsMod: LONGINT; ioVAtrb: INTEGER; ioVNmFls: INTEGER; ioVBitMap: INTEGER; ioAllocPtr: INTEGER; ioVNmAlBlks: INTEGER; ioVAlBlkSiz: LONGINT; ioVClpSiz: LONGINT; ioAlBlSt: INTEGER; ioVNxtCNID: LONGINT; ioVFrBlk: INTEGER; ioVSigWord: INTEGER; ioVDrvInfo: INTEGER; ioVDRefNum: INTEGER; ioVFSID: INTEGER; ioVBkUp: LONGINT; ioVSeqNum: INTEGER; ioVWrCnt: LONGINT; ioVFilCnt: LONGINT; ioVDirCnt: LONGINT; ioVFndrInfo: ARRAY [1..8] OF LONGINT); AccessParam: (filler3: INTEGER; ioDenyModes: INTEGER; {access rights data} filler4: INTEGER; filler5: SignedByte; ioACUser: SignedByte; {access rights for directory only} filler6: LONGINT; ioACOwnerID: LONGINT; {owner ID} ioACGroupID: LONGINT; {group ID} ioACAccess: LONGINT); {access rights} ObjParam: (filler7: INTEGER; ioObjType: INTEGER; {function code} ioObjNamePtr: Ptr; {ptr to returned creator/group name} ioObjID: LONGINT); {creator/group ID} CopyParam: (ioDstVRefNum: INTEGER; {destination vol identifier} filler8: INTEGER; ioNewName: Ptr; {ptr to destination pathname} ioCopyName: Ptr; {ptr to optional name} ioNewDirID: LONGINT); {destination directory ID} WDParam: (filler9: INTEGER; ioWDIndex: INTEGER; ioWDProcID: LONGINT; ioWDVRefNum: INTEGER; filler10: INTEGER; filler11: LONGINT; filler12: LONGINT; filler13: LONGINT; ioWDDirID: LONGINT); FIDParam: (filler14: LONGINT; ioDestNamePtr: StringPtr; filler15: LONGINT; ioDestDirID: LONGINT; filler16: LONGINT; filler17: LONGINT; ioSrcDirID: LONGINT; END; æC »FileParam Variant ( ParamBlockRec and HParamBlockRec) The fileParam variants of ParamBlockRec and HParamBlockRec are identical, with one exception: The field ioDirID in HParamBlockRec is called ioFlNum in ParamBlockRec. The fields of the fileParam variant of HParamBlockRec are as follows: •••Refer to Technical Note #204:••• fileParam: (ioFRefNum: INTEGER; {path reference number} ioFVersNum: SignedByte; {version number} filler1: SignedByte; {not used} ioFDirIndex: INTEGER; {index} ioFlAttrib: SignedByte; {file attributes} ioFlVersNum: SignedByte; {version number} ioFlFndrInfo: FInfo; {information used by the Finder} ioDirID: LONGINT; {directory ID or file number} ioFlStBlk: INTEGER; {first allocation block of data fork} ioFlLgLen: LONGINT; {logical end-of-file of data fork} ioFlPyLen: LONGINT; {physical end-of-file of data fork} ioFlRStBlk: INTEGER; {first allocation block of resource fork} ioFlRLgLen: LONGINT; {logical end-of-file of resource fork} ioFlRPyLen: LONGINT; {physical end-of-file of resource fork} ioFlCrDat: LONGINT; {date and time of creation} ioFlMdDat: LONGINT); {date and time of last modification} IOFDirIndex can be used with the PBGetFInfo and PBHGetFInfo to index through the files in a given directory. Warning: When used with GetFileInfo, ioFDirIndex will index only the files in a directory. To index both files and directories, you can use ioFDirIndex with PBGetCatInfo. IOFlAttrib contains the following file attributes: Bit Meaning 0 Set if file is locked 2 Set if resource fork is open 3 Set if data fork is open 4 Set if a directory 7 Set if file (either fork) is open When passed to a routine, ioDirID contains a directory ID; it can be used to refer to a directory or, in conjuction with a partial pathname from that directory, to other files and directories. If both a directory ID and a working directory reference number are provided, the directory ID is used to identify the directory on the volume indicated by the working directory reference number. In other words, a directory ID specified by the caller will override the working directory referred to by the working directory reference number. If you don’t want this to happen, you can set ioDirID to 0. (If no directory is specified through a working directory reference number, the root directory ID will be used.) When returned from a routine, ioDirID contains the file number of a file; most programmers needn’t be concerned with file numbers, but those interested can read the section “Data Organization on Volumes”. IOFlStBlk and ioFlRStBlk contain 0 if the file’s data or resource fork is empty, respectively; they’re used only with flat volumes. The date and time in the ioFlCrDat and ioFlMdDat fields are specified in seconds since midnight, January 1, 1904. »VolumeParam Variant (ParamBlockRec) When you call GetVolInfo, you’ll use the volumeParam variant of ParamBlockRec: volumeParam: (filler2: LONGINT; {not used} ioVolIndex: INTEGER; {index} ioVCrDate: LONGINT; {date and time of initialization} ioVLsBkUp: LONGINT; {date and time of last modification} ioVAtrb: INTEGER; {volume attributes} ioVNmFls: INTEGER; {number of files in root directory} ioVDirSt: INTEGER; {first block of directory} ioVBlLn: INTEGER; {length of directory in blocks} ioVNmAlBlks: INTEGER; {number of allocation blocks} ioVAlBlkSiz: LONGINT; {size of allocation blocks} ioVClpSiz: LONGINT; {number of bytes to allocate} ioAlBlSt: INTEGER; {first block in volume block map} ioVNxtFNum: LONGINT; {next unused file number} ioVFrBlk: INTEGER); {number of unused allocation blocks} IOVolIndex can be used to index through all the mounted volumes; using an index of 1 accesses the first volume mounted, and so on. (For more information on indexing, see the section “Indexing” above.) IOVLsBkUp contains the date and time the volume information was last modified (this is not necessarily when it was flushed). (This field is not modified when information is written to a file.) Note: The name ioVLsBkUp is actually a misnomer; this field has always contained the date and time of the last modification to the volume, not the last backup. Most programmers needn’t be concerned with the remaining parameters, but interested programmers can read the section “Data Organization on Volumes”. »VolumeParam Variant (HParamBlockRec) When you call HGetVInfo and SetVolInfo, you’ll use the volumeParam variant of HParamBlockRec. This is a superset of the volumeParam variant of ParamBlockRec; the names and functions of certain fields have been changed, and new fields have been added: volumeParam: (filler2: LONGINT; {not used} ioVolIndex: INTEGER; {index} ioVCrDate: LONGINT; {date and time of initialization} ioVLsMod: LONGINT; {date and time of last modification} ioVAtrb: INTEGER; {volume attributes} ioVNmFls: INTEGER; {number of files in root directory} ioVBitMap: INTEGER; {first block of volume bit map} ioAllocPtr: INTEGER; {block at which next new file starts} ioVNmAlBlks: INTEGER; {number of allocation blocks} ioVAlBlkSiz: LONGINT; {size of allocation blocks} ioVClpSiz: LONGINT; {number of bytes to allocate} ioAlBlSt: INTEGER; {first block in volume block map} ioVNxtCNID: LONGINT; {next unused file number} ioVFrBlk: INTEGER; {number of unused allocation blocks} ioVSigWord: INTEGER; {volume signature} ioVDrvInfo: INTEGER; {drive number} ioVDRefNum: INTEGER; {driver reference number} ioVFSID: INTEGER; {file system handling this volume} ioVBkUp: LONGINT; {date and time of last backup} ioVSeqNum: INTEGER; {used internally} ioVWrCnt LONGINT; {volume write count} ioVFilCnt: LONGINT; {number of files on volume} ioVDirCnt: LONGINT; {number of directories on volume} ioVFndrInfo: ARRAY[1..8] OF LONGINT); {information used by the Finder} IOVolIndex can be used to index through all the mounted volumes; using an index of 1 accesses the first volume mounted, and so on. (For more information on indexing, see the section “Indexing” above.) IOVLsMod contains the date and time the volume information was last modified (this is not necessarily when it was flushed). (This field is not modified when information is written to a file.) Note: IOVLsMod replaces the field ioVLsBkUp in ParamBlockRec. The name ioVLsBkUp was actually a misnomer; this field has always contained the date and time of the last modification, not the last backup. Another field, ioVBkUp, contains the date and time of the last backup. IOVClpSiz can be used to set the volume clump size in bytes; it’s used for files that don’t have a clump size defined as part of their file information in the catalog. To promote file contiguity and avoid fragmentation, space is allocated to a file not in allocation blocks but in clumps. A clump is a group of contiguous allocation blocks. The clump size is always a multiple of the allocation block size; it’s the minimum number of bytes to allocate each time the Allocate function is called or the end-of-file is reached during the Write routine. IOVSigWord contains a signature word identifying the type of volume; it’s $D2D7 for flat directory volumes and $4244 for hierarchical directory volumes. The drive number of the drive containing the volume is returned in ioDrvInfo. For on-line volumes, ioVDRefNum returns the reference number of the I/O driver for the drive identified by ioDrvInfo. IOVFSID is the file-system identifier. It indicates which file system is servicing the volume; it’s 0 for File Manager volumes and nonzero for volumes handled by an external file system. IOVBkUp specifies the date and time the volume was last backed up (it’s 0 if never backed up). IOVNmFls contains the number of files in the root directory. IOVFilCnt contains the total number of files on the volume, while ioVDirCnt contains the total number of directories (not including the root directory). Most programmers needn’t be concerned with the other parameters, but interested programmers can read the section “Data Organization on Volumes”. HParamBlockRec, described above, has been extended to support a shared environment with the addition of AccessParam, ObjParam, CopyParam, and WDParam, as shown below. (The complete HParamBlockRec data type is shown in the summary.) AccessParam: (filler3: INTEGER; ioDenyModes: INTEGER; {access rights data} filler4: INTEGER; filler5: Signed Byte; ioACUser: Signed Byte; {access rights for directory only} filler6: LONGINT; ioACOwnerID: LONGINT; {owner ID} ioACGroupID: LONGINT; {group ID} ioACAccess: LONGINT); {access rights} ObjParam: (filler7: INTEGER; ioObjType: INTEGER; {function code} ioObjNamePtr: Ptr; {ptr to returned creator/group name} ioObjID: LONGINT; {creator/group ID} ioReqCount: LONGINT; {size of buffer area} ioActCount: LONGINT); {length of vol parms data} CopyParam: (ioDstVRefNum: INTEGER; {destination vol identifier} filler8: INTEGER; ioNewName: Ptr; {ptr to destination pathname} ioCopyName: Ptr; {ptr to optional name} ioNewDirID: LONGINT); {destination directory ID} WDParam: (filler9: INTEGER; ioWDIndex: INTEGER; ioWDProcID: LONGINT; ioWDVRefNum: INTEGER; filler10: INTEGER; filler11: LONGINT; filler12: LONGINT; filler13: LONGINT; ioWDDirID: LONGINT); æKY NumVersion æFp Files.p æT RECORD æD NumVersion = PACKED RECORD CASE INTEGER OF 0: (majorRev: SignedByte; {1st part of version number in BCD} minorRev: 0..9; {2nd part is 1 nibble in BCD} bugFixRev: 0..9; {3rd part is 1 nibble in BCD} stage: SignedByte; {stage code: dev, alpha, beta, final} nonRelRev: SignedByte); {revision level of non-released version} 1: (version: LONGINT); {to use all 4 fields at one time} END; { Numeric version part of 'vers' resource } æC æKY VersRec VersRecPtr VersRecHndl æFp Files.p æT RECORD æD VersRecPtr = ^VersRec; VersRecHndl = ^VersRecPtr; VersRec = RECORD numericVersion: NumVersion; {encoded version number} countryCode: INTEGER; {country code from intl utilities} shortVersion: Str255; {version number string - worst case} reserved: Str255; {longMessage string packed after shortVersion} END; { 'vers' resource format } æC æKY PBHGetVolParms æFp Files.p æT FUNCTION æD FUNCTION PBHGetVolParms(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHGetVolParms(paramBlock,async); æRI V-392, VI æC Trap macro _GetVolParms Parameter block Æ 12 ioCompletion long pointer to completion routine ¨ 16 ioResult word error result code Æ 18 ioFileName long volume name specifier Æ 22 ioVRefNum word volume refNum ¨ 32 ioBuffer long pointer to attributes buffer Æ 36 ioReqCount long size of buffer area ¨ 40 ioActCount long length of volume parms data <See the description in Volume V. We have a new version of the attributes buffer and new values for vMAttrib:> Attributes buffer 0 vMVersion word version number (02 for this version) 2 vMAttrib long attributes (detailed below) 6 vMLocalHand long handle to private data for shared volumes 10 vMServerAdr long AppleTalk server address (0 if not supported) 14 vMVolumeGrade long Approximate speed rating of volume 18 vMAltPrivModel word Alternative privilege model supported (two values currently defined: 0 for an HFS volume; 1 for an A/UX volume) Bit positions in vMAttrib 31 bLimitFCBs Limit the number of FCBs used during copying to 8 instead of 16. 30 bLocalWList Use the returned shared volume handle for the Finder’s local window list. 29 bNoMiniFndr Disable Mini Finder menu item. 28 bNoVNEdit Lock volume name against editing. 27 bNoLclSync Do not let Finder change the modification date. 26 bTrshOffLine Zoom volume when it goes off line to the Trash and when it’s unmounted. 25 bNoSwitchTo Do not switch-launch to any application on the volume. 24-21 Reserved. Server volumes return these bits set. All other volumes return these bits cleared. 20 bNoDeskItems Do not place objects on the Finder desktop. 19 bNoBootBlks Not a startup volume. Startup menu item disabled. Bootblocks not copied. 18 bAccessCntl Volume supports AppleTalk AFP access control interfaces. The functions GetLoginInfo, GetDirAccess, SetDirAccess, MapID, and MapName are supported. Special folder icons are used. Access Privileges menu item is enabled for disk and folder items. The privileges field of GetCatInfo calls are assumed to be valid. 17 bNoSysDir Volume doesn’t support a system directory. Do not switch launch to this volume. 16 bExtFSVol Volume is an external file system volume. Disk initialization package is not called. Erase Disk menu item is disabled. 15 bHasOpenDeny Volume supports _OpenDeny and _OpenRFDeny. For copy operations, source files are opened with enable read/deny write and destination files are opened enable write/deny read and write. 14 bHasCopyFile Volume supports _CopyFile. _CopyFile is used in copy and duplicate operations if both source and destination volumes have same server address. 13 bHasMoveRename Volume supports _MoveRename. 12 bHasNewDesk Volume supports all of the new desktop functions (described in Volume V). 11 bHasShortName Volume supports a name that fits the requirements of another file system. 10 bHasFolderLock Folder is locked. 9 bHasPersonalAccessPrivileges Macintosh File Share is running. 8 bHasUserGroupList Volume supports the Users and Groups file and thus the AFP privilege functions. 7 bHasCatSearch Volume supports PBCatSearch. 6 bHasFileIDs Volume supports fileID functions 5 For internal use only 4-0 Reserved. All volumes return these bits clear. æKY PBHGetLogInInfo æFp Files.p æT FUNCTION æD FUNCTION PBHGetLogInInfo(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHGetLogInInfo(paramBlock,async); æRI V-393 æC Trap macro _GetLogInInfo Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 22 ioVRefNum word volume refNum <-- 26 ioObjType word log in method <-- 28 ioObjNamePtr long ptr to log in name buffer PBHGetLogInInfo returns the method used for log-in and the user name specified at log-in time for the volume. The log-in user name is returned as a Pascal string in ioObjNamePtr. The maximum size of the user name is 31 characters. The log-in method type is returned in ioObjType. æKY PBHGetDirAccess æFp Files.p æT FUNCTION æD FUNCTION PBHGetDirAccess(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHGetDirAccess(paramBlock,async); æRI V-394 æC Trap macro _GetDirAccess Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 18 ioFileName long directory name --> 22 ioVRefNum word volume refNum <-- 36 ioACOwnerID long owner ID <-- 40 ioACGroupID long group ID <-- 44 ioACAccess long access rights --> 48 ioDirID long directory ID PBHGetDirAccess returns access control information for the folder pointed to by the ioDirID/ioFIleName pair. ioACOwnerID will return the ID for the folder’s owner. ioACGroupID will return the ID for the folder’s primary group. The access rights are returned in ioACAccess. A fnfErr is returned if the pathname does not point to a valid directory. An AccessDenied error is returned if the user does not have the correct access rights to examine this directory. æKY PBHSetDirAccess æFp Files.p æT FUNCTION æD FUNCTION PBHSetDirAccess(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHSetDirAccess(paramBlock,async); æRI V-394 æC Trap macro _SetDirAccess Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 18 ioFileName long pathname identifier --> 22 ioVRefNum word volume refNum --> 36 ioACOwnerID long owner ID --> 40 ioACGroupID long group ID --> 44 ioACAccess long access rights --> 48 ioDirID long directory ID PBHSetDirAccess allows you to change the access rights to a folder pointed to by the ioFileName/ioDirID pair. IOACOwnerID contains the new owner ID. IOACGroupID contains the group ID. IOACAccess contains the folder’s access rights. You cannot set the owner bit or the user’s rights of the directory. To change the owner or group, you should set the ioACOwnerID or ioACGroupID field with the appropriate ID of the new owner/group. You must be the owner of the directory to change the owner or group ID. A fnfErr is returned if the pathname does not point to a valid directory. An AccessDenied error is returned if you do not have the correct access rights to modify the parameters for this directory. A paramErr is returned if you try to set the owner bit or user’s rights bits. æKY PBHMapID æFp Files.p æT FUNCTION æD FUNCTION PBHMapID(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHMapID(paramBlock,async); æRI V-395 æC Trap macro _MapID Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 18 ioFileName long pathname identifier --> 22 ioVRefNum word volume refNum --> 26 ioObjType word function code <-- 28 ioObjNamePtr long ptr to retrnd creator/group name --> 32 ioObjID long creator/group ID PBHMapID returns the name of a user or group given its unique ID. IOObjID contains the ID to be mapped. The value zero for ioObjID is special cased and will always return a NIL name. AppleShare uses this to signify <Any User>. IOObjType is the mapping function code; it’s 1 if you’re mapping an owner ID to owner name or 2 if you’re mapping a group ID to a group name. The name is returned as a Pascal string in ioObjNamePtr. The maximum size of the name is 31 characters. A fnfErr is returned if an unrecognizable owner or group ID is passed. æKY PBHMapName æFp Files.p æT FUNCTION æD FUNCTION PBHMapName(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHMapName(paramBlock,async); æRI V-395 æC Trap macro _MapName Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 18 ioFileName long volume identifier (may be NIL) --> 22 ioVRefNum word volume refNum --> 28 ioObjNamePtr long owner or group name --> 26 ioObjType word function code <-- 32 ioObjID long creator/group ID PBHMapName returns the unique user ID or group ID given its name. The name is passed as a string in ioObjNamePtr. If a NIL name is passed, the ID returned will always be zero. The maximum size of the name is 31 characters. IOObjType is the mapping function code; it’s 3 if you’re mapping an owner name to owner ID or 4 if you’re mapping a group name to a group ID. IOObjID will contain the mapped ID. A fnfErr is returned if an unrecognizable owner or group name is passed. æKY PBHCopyFile æFp Files.p æT FUNCTION æD FUNCTION PBHCopyFile(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHCopyFile(paramBlock,async); æRI V-396 æC Trap macro _CopyFile Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 18 ioFileName long ptr to source pathname --> 22 ioVRefNum word source vol identifier --> 24 ioDstVRefNum word destination vol identifier --> 28 ioNewName long ptr to destination pathname --> 32 ioCopyName long ptr to optional name (may be NIL) --> 36 ioNewDirID long destination directory ID --> 48 ioDirID long source directory ID PBHCopyFile duplicates a file on the volume and optionally renames it. It is an optional call for AppleShare file servers. You should examine the returned flag information in the PBHGetVolParms call to see if this volume supports CopyFile. For AppleShare file servers, the source and destination pathnames must indicate the same file server; however, it may point to a different volume for that file server. A useful way to tell if two file server volumes are on the same file server is to make the GetVolParms call and compare the server addresses returned. The server will open source files with read/deny write enabled and destination files with write/deny read and write enabled. IOVRefNum contains a source volume identifier. The source pathname is determined by the ioFileName/ioDirID pair. IODstVRefNum contains a destination volume identifier. AppleShare 1.0 required that it be an actual volume reference number; however, on future versions it can be a WDRefNum. The destination pathname is determined by the ioNewName/ioNewDirID pair. IOCopyName may contain an optional string used in renaming the file. If it is non-NIL then the file copy will be renamed to the specified name in ioCopyName. A fnfErr is returned if the source pathname does not point to an existing file or the destination pathname does not point to an existing directory. An AccessDenied error is returned if the user does not have the right to read the source or write to the destination. A dupFnErr is returned if the destination already exists. A DenyConflict error is returned if either the source or destination file could not be opened under the access modes described above. æKY PBHMoveRename æFp Files.p æT FUNCTION æD FUNCTION PBHMoveRename(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHMoveRename(paramBlock,async); æRI V-397 æC Trap macro _MoveRename Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 18 ioFileName long ptr to source pathname --> 22 ioVRefNum word source vol identifier --> 28 ioNewName long ptr to destination pathname --> 32 ioBuffer long ptr to optional name (may be NIL) --> 36 ioNewDirID long destination directory ID --> 48 ioDirID long source directory ID PBHMoveRename allows you to move (not copy) an item and optionally to rename it. The source and destination pathnames must point to the same file server volume. IOVRefNum contains a source volume identifier. The source pathname is specified by the ioFileName/ioDirID pair. The destination pathname is specified by the ioNewName/ioNewDirID pair. IOBuffer may contain an optional string used in renaming the item. If it is non-NIL then the moved object will be renamed to the specified name in ioBuffer. A fnfErr is returned if the source pathname does not point to an existing object. An AccessDenied error is returned if the user does not have the right to move the object. A dupFnErr is returned if the destination already exists. A badMovErr is returned if an attempt is made to move a directory into one of its descendent directories. æKY PBHOpenDeny æFp Files.p æT FUNCTION æD FUNCTION PBHOpenDeny(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHOpenDeny(paramBlock,async); æRI V-398 æC Trap macro _OpenDeny Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 18 ioFileName long ptr to pathname --> 22 ioVRefNum word vol identifier <-- 24 ioRefNum word file refNum --> 26 ioDenyModes word access rights data --> 48 ioDirID long directory ID PBHOpenDeny opens a file’s data fork under specific access rights. It creates an access path to the file having the name pointed to by ioFileName/ioDirID. The path reference number is returned in ioRefNum. IODenyModes contains a word of access rights information. The format for these access rights is: bits 15–6 Reserved—should be cleared. 5 If set, other writers are denied access. 4 If set, other readers are denied access. 3–2 Reserved—should be cleared. 1 If set, write permission requested. 0 If set, read permission requested. A fnfErr is returned if the input specification does not point to an existing file. A permErr is returned if the file is already open and you cannot open it under the deny modes that you have specified. An opWrErr is returned if you have asked for write permission and the file is already opened by you for write. The already opened path reference number is returned in ioRefNum. An AccessDenied error is returned if you do not have the right to access the file. æKY PBHOpenRFDeny æFp Files.p æT FUNCTION æD FUNCTION PBHOpenRFDeny(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHOpenRFDeny(paramBlock,async); æRI V-398 æC Trap macro _OpenRFDeny Parameter block --> 12 ioCompletion long optional completion routine ptr <-- 16 ioResult word error result code --> 18 ioFileName long ptr to pathname --> 22 ioVRefNum word vol identifier <-- 24 ioRefNum word file refNum --> 26 ioDenyModes word access rights data --> 48 ioDirID long directory ID PBHOpenRFDeny opens a file’s resource fork under specific access rights. It creates an access path to the file having the name pointed to by ioFileName/ioDirID. The path reference number is returned in ioRefNum. The format of the access rights data contained in ioDenyModes is described under the OpenDeny call. A fnfErr is returned if the input specification does not point to an existing file. A permErr is returned if the file is already open and you cannot open it under the deny modes that you have specified. An opWrErr is returned if you have asked for write permission and the file is already opened by you for write. The already-opened path reference number is returned in ioRefNum. An AccessDenied error is returned if you do not have the right to access the file. æKY PBOpen æFp Files.p æT FUNCTION æD FUNCTION PBOpen(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBOpen(paramBlock,async); æRI II-108 æC Trap macro _Open Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word <-- 24 ioRefNum word --> 26 ioVersNum byte --> 27 ioPermssn byte --> 28 ioMisc pointer PBOpen creates an access path to the file having the name pointed to by ioNamePtr (and on flat volumes, the version number ioVersNum) on the volume specified by ioVRefNum. A path reference number is returned in ioRefNum. IOMisc either points to a portion of memory (522 bytes) to be used as the access path’s buffer, or is NIL if you want the volume buffer to be used instead. Warning: All access paths to a single file that’s opened multiple times should share the same buffer so that they will read and write the same data. IOPermssn specifies the path’s read/write permission. A path can be opened for writing even if it accesses a file on a locked volume, and an error won’t be returned until a PBWrite, PBSetEOF, or PBAllocate call is made. If you attempt to open a locked file for writing, PBOpen will return permErr as its function result. If you request exclusive read/write permission but another access path already has write permission (whether write only, exclusive read/write, or shared read/write), PBOpen will return the reference number of the existing access path in ioRefNum and opWrErr as its function result. Similarly, if you request shared read/write permission but another access path already has exclusive read/write permission, PBOpen will return the reference number of the access path in ioRefNum and opWrErr as its function result. Result codes noErr No error bdNamErr Bad file name extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing permErr Attempt to open locked file for writing tmfoErr Too many files open æKY PBClose æFp Files.p æT FUNCTION æD FUNCTION PBClose(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBClose(paramBlock,async); æRI II-114 æC Trap macro _Close Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word PBClose writes the contents of the access path buffer specified by ioRefNum to the volume and removes the access path. Warning: Some information stored on the volume won’t be correct until PBFlushVol is called. Result codes noErr No error extFSErr External file system fnfErr File not found fnOpnErr File not open ioErr I/O error nsvErr No such volume rfNumErr Bad reference number æKY PBRead æFp Files.p æT FUNCTION æD FUNCTION PBRead(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBRead(paramBlock,async); æRT 187 æRI II-110 æC Trap macro _Read Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word --> 32 ioBuffer pointer --> 36 ioReqCount long word <-- 40 ioActCount long word --> 44 ioPosMode word <-> 46 ioPosOffset long word PBRead attempts to read ioReqCount bytes from the open file whose access path is specified by ioRefNum, and transfer them to the data buffer pointed to by ioBuffer. The position of the mark is specified by ioPosMode and ioPosOffset. If you try to read past the logical end-of-file, PBRead moves the mark to the end-of-file and returns eofErr as its function result. After the read is completed, the mark is returned in ioPosOffset and the number of bytes actually read is returned in ioActCount. Result codes noErr No error eofErr End-of-file extFSErr External file system fnOpnErr File not open ioErr I/O error paramErr Negative ioReqCount rfNumErr Bad reference number æKY PBWrite æFp Files.p æT FUNCTION æD FUNCTION PBWrite(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBWrite(paramBlock,async); æRT 187 æRI II-110 æC •••Refer to Technical Note #187:••• Trap macro _Write Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word --> 32 ioBuffer pointer --> 36 ioReqCount long word <-- 40 ioActCount long word --> 44 ioPosMode word <-> 46 ioPosOffset long word PBWrite takes ioReqCount bytes from the buffer pointed to by ioBuffer and attempts to write them to the open file whose access path is specified by ioRefNum. The position of the mark is specified by ioPosMode and ioPosOffset. After the write is completed, the mark is returned in ioPosOffset and the number of bytes actually written is returned in ioActCount. Result codes noErr No error dskFulErr Disk full fLckdErr File locked fnOpnErr File not open ioErr I/O error paramErr Negative ioReqCount posErr Attempt to position before start of file rfNumErr Bad reference number vLckdErr Software volume lock wPrErr Hardware volume lock wrPermErr Read/write permission doesn’t allow writing æKY PBGetVInfo æFp Files.p æT FUNCTION æD FUNCTION PBGetVInfo(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetVInfo(paramBlock,async); æRT 24, 44, 157 æRI II-104, IV-129, N24-1, N44-2, N157 æC Trap macro _GetVolInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-> 18 ioNamePtr pointer <-> 22 ioVRefNum word --> 28 ioVolIndex word <-- 30 ioVCrDate long word <-- 34 ioVLsBkUp long word <-- 38 ioVAtrb word <-- 40 ioVNmFls word <-- 42 ioVDirSt word <-- 44 ioVBlLn word <-- 46 ioVNmAlBlks word <-- 48 ioVAlBlkSiz long word <-- 52 ioVClpSiz long word <-- 56 ioAlBlSt word <-- 58 ioVNxtFNum long word <-- 62 ioVFrBlk word PBGetVInfo returns information about the specified volume. If ioVolIndex is positive, the File Manager attempts to use it to find the volume; for instance, if ioVolIndex is 2, the File Manager will attempt to access the second mounted volume. If ioVolIndex is negative, the File Manager uses ioNamePtr and ioVRefNum in the standard way (described in the section “Specifying Volumes, Directories, and Files”) to determine which volume. If ioVolIndex is 0, the File Manager attempts to access the volume by using ioVRefNum only. The volume reference number is returned in ioVRefNum, and a pointer to the volume name is returned in ioNamePtr (unless ioNamePtr is NIL). If a working directory reference number is passed in ioVRefNum (or if the default directory is a subdirectory), the number of files and directories in the specified directory (the directory’s valence) will be returned in ioVNmFls. Also, the volume reference number won’t be returned; ioVRefNum will still contain the working directory reference number. Warning: IOVNmAlBlks and ioVFrBlks, which are actually unsigned integers, are clipped to 31744 ($7C00) regardless of the size of the volume. Result codes noErr No error nsvErr No such volume paramErr No default volume æKY PBGetVol æFp Files.p æT FUNCTION æD FUNCTION PBGetVol(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetVol(paramBlock,async); æRI II-104, IV-131 æC Trap macro _GetVol Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-- 18 ioNamePtr pointer <-- 22 ioVRefNum word PBGetVol returns a pointer to the name of the default volume in ioNamePtr (unless ioNamePtr is NIL) and its volume reference number in ioVRefNum. If a default directory was set with a previous PBSetVol call, a pointer to its name will be returned in ioNamePtr and its working directory reference number in ioVRefNum. Result codes noErr No error nsvErr No default volume æKY PBSetVol æFp Files.p æT FUNCTION æD FUNCTION PBSetVol(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetVol(paramBlock,async); æRI II-105, IV-132 æC Trap macro _SetVol Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word PBSetVol sets the default volume to the mounted volume specified by ioNamePtr or ioVRefNum. On hierarchical volumes, PBSetVol also sets the root directory as the default directory. Result codes noErr No error bdNamErr Bad volume name nsvErr No such volume paramErr No default volume æKY PBFlushVol æFp Files.p æT FUNCTION æD FUNCTION PBFlushVol(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBFlushVol(paramBlock,async); æMM æRI II-105, IV-133 æC Trap macro _FlushVol Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word On the volume specified by ioNamePtr or ioVRefNum, PBFlushVol writes descriptive information about the volume, the contents of the associated volume buffer, and all access path buffers for the volume (if they’ve changed since the last time PBFlushVol was called). Note: The date and time of the last modification to the volume are set when the modification is made, not when the volume is flushed. Result codes noErr No error bdNamErr Bad volume name extFSErr External file system ioErr I/O error nsDrvErr No such drive nsvErr No such volume paramErr No default volume æKY PBCreate æFp Files.p æT FUNCTION æD FUNCTION PBCreate(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBCreate(paramBlock,async); æRI II-107, IV-145 æC Trap macro _Create Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 26 ioFVersNum byte PBCreate creates a new file (both forks) having the name pointed to by ioNamePtr (and on flat volumes, the version number ioVersNum) on the volume specified by ioVRefNum. The new file is unlocked and empty. The date and time of its creation and last modification are set to the current date and time. If the file created isn’t temporary (that is, if it will exist after the application terminates), the application should call PBSetFInfo (after PBCreate) to fill in the information needed by the Finder. Assembly-language note: If a desk accessory creates a file, it should always create it in the directory containing the system folder. The working directory reference number for this directory is stored in the global variable BootDrive; you can pass it in ioVRefNum. Result codes noErr No error bdNamErr Bad file name dupFNErr Duplicate file name and version dirFulErr File directory full extFSErr External file system ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBDelete æFp Files.p æT FUNCTION æD FUNCTION PBDelete(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDelete(paramBlock,async); æRI II-119, IV-147 æC Trap macro _Delete Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 26 ioFVersNum byte PBDelete removes the closed file having the name pointed to by ioNamePtr (and on flat volumes, the version number ioVersNum) from the volume pointed to by ioVRefNum. PBHDelete can be used to delete an empty directory as well. Note: This function will delete both forks of the file. Result codes noErr No error bdNamErr Bad file name extFSErr External file system fBsyErr File busy, directory not empty, or working directory control block open fLckdErr File locked fnfErr File not found nsvErr No such volume ioErr I/O error vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBOpenRF æFp Files.p æT FUNCTION æD FUNCTION PBOpenRF(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBOpenRF(paramBlock,async); æMM æRT 74 æRI II-109, IV-137 æC Trap macro _OpenRF Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word <-- 24 ioRefNum word --> 26 ioVersNum byte --> 27 ioPermssn byte --> 28 ioMisc pointer PBOpenRF is identical to PBOpen, except that it opens the file’s resource fork instead of its data fork. Note: Normally you should access a file’s resource fork through the routines of the Resource Manager rather than the File Manager. PBOpenRF doesn’t read the resource map into memory; it’s really only useful for block-level operations such as copying files. Result codes noErr No error bdNamErr Bad file name extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing permErr Attempt to open locked file for writing tmfoErr Too many files open æKY PBRename æFp Files.p æT FUNCTION æD FUNCTION PBRename(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBRename(paramBlock,async); æRI II-118, IV-153 æC Trap macro _Rename Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 26 ioVersNum byte --> 28 ioMisc pointer Given a pointer to a file name in ioNamePtr (and on flat volumes, a version number in ioVersNum), PBRename changes the name of the file to the name pointed to by ioMisc. (If the name pointed to by ioNamePtr contains one or more colons, so must the name pointed to by ioMisc.) Access paths currently in use aren’t affected. Given a pointer to a volume name in ioNamePtr or a volume reference number in ioVRefNum, it changes the name of the volume to the name pointed to by ioMisc. If a volume to be renamed is specified by its volume reference number, ioNamePtr can be NIL. Warning: If a volume to be renamed is specified by its volume name, be sure that it ends with a colon, or Rename will consider it a file name. Result codes noErr No error bdNamErr Bad file name dirFulErr File directory full dupFNErr Duplicate file name and version extFSErr External file system fLckdErr File locked fnfErr File not found fsRnErr Problem during rename ioErr I/O error nsvErr No such volume paramErr No default volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBGetFInfo æFp Files.p æT FUNCTION æD FUNCTION PBGetFInfo(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetFInfo(paramBlock,async); æRT 24 æRI II-115, IV-148, N24-1, N68-1 æC Trap macro _GetFileInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-> 18 ioNamePtr pointer --> 22 ioVRefNum word <-- 24 ioFRefNum word --> 26 ioFVersNum byte --> 28 ioFDirIndex word <-- 30 ioFlAttrib byte <-- 31 ioFlVersNum byte <-- 32 ioFlFndrInfo 16 bytes <-- 48 ioFlNum long word <-- 52 ioFlStBlk word <-- 54 ioFlLgLen long word <-- 58 ioFlPyLen long word <-- 62 ioFlRStBlk word <-- 64 ioFlRLgLen long word <-- 68 ioFlRPyLen long word <-- 72 ioFlCrDat long word <-- 76 ioFlMdDat long word PBGetFInfo returns information about the specified file. If ioFDirIndex is positive, the File Manager returns information about the file whose directory index is ioFDirIndex on the volume specified by ioVRefNum. (See the section “Data Organization on Volumes” if you’re interested in using this method.) Note: If a working directory reference number is specified in ioVRefNum, the File Manager returns information about the file whose directory index is ioFDirIndex in the specified directory. If ioFDirIndex is negative or 0, the File Manager returns information about the file having the name pointed to by ioNamePtr (and on flat volumes, the version number ioFVersNum) on the volume specified by ioVRefNum. If the file is open, the reference number of the first access path found is returned in ioFRefNum, and the name of the file is returned in ioNamePtr (unless ioNamePtr is NIL). Result codes noErr No error bdNamErr Bad file name extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume paramErr No default volume æKY PBSetFInfo æFp Files.p æT FUNCTION æD FUNCTION PBSetFInfo(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetFInfo(paramBlock,async); æRI II-116, IV-150 æC Trap macro _SetFileInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 26 ioFVersNum byte --> 32 ioFlFndrInfo 16 bytes --> 72 ioFlCrDat long word --> 76 ioFlMdDat long word PBSetFInfo sets information (including the date and time of creation and modification, and information needed by the Finder) about the file having the name pointed to by ioNamePtr (and on flat volumes, the version number ioFVersNum) on the volume specified by ioVRefNum. You should call PBGetFInfo just before PBSetFInfo, so the current information is present in the parameter block. Result codes noErr No error bdNamErr Bad file name extFSErr External file system fLckdErr File locked fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBSetFLock æFp Files.p æT FUNCTION æD FUNCTION PBSetFLock(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetFLock(paramBlock,async); æRI II-116, IV-151 æC Trap macro _SetFilLock Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 26 ioFVersNum byte PBSetFLock locks the file having the name pointed to by ioNamePtr (and on flat volumes, the version number ioFVersNum) on the volume specified by ioVRefNum. Access paths currently in use aren’t affected. Result codes noErr No error extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBRstFLock æFp Files.p æT FUNCTION æD FUNCTION PBRstFLock(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBRstFLock(paramBlock,async); æRI II-117, IV-152 æC Trap macro _RstFilLock Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 26 ioFVersNum byte PBRstFLock unlocks the file having the name pointed to by ioNamePtr (and on flat volumes, the version number ioFVersNum) on the volume specified by ioVRefNum. Access paths currently in use aren’t affected. Result codes noErr No error extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBSetFVers æFp Files.p æT FUNCTION æD FUNCTION PBSetFVers(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetFVers(paramBlock,async); æRI II-117, IV-153 æC Trap macro _SetFilType Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 26 ioVersNum byte --> 28 ioMisc byte PBSetFVers has no effect on hierarchical volumes. On flat volumes, PBSetFVers changes the version number of the file having the name pointed to by ioNamePtr and version number ioVersNum, on the volume specified by ioVRefNum, to the version number stored in the high-order byte of ioMisc. Access paths currently in use aren’t affected. Result codes noErr No error bdNamErr Bad file name dupFNErr Duplicate file name and version extFSErr External file system fLckdErr File locked fnfErr File not found nsvErr No such volume ioErr I/O error paramErr No default volume vLckdErr Software volume lock wPrErr Hardware volume lock wrgVolTypErr Attempt to perform hierarchical operation on a flat volume æKY PBAllocate æFp Files.p æT FUNCTION æD FUNCTION PBAllocate(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBAllocate(paramBlock,async); æRI II-113, IV-143 æC Trap macro _Allocate Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word --> 36 ioReqCount long word <-- 40 ioActCount long word PBAllocate adds ioReqCount bytes to the open file whose access path is specified by ioRefNum, and sets the physical end-of-file to one byte beyond the last block allocated. The number of bytes actually allocated is rounded up to the nearest multiple of the allocation block size, and returned in ioActCount. If there isn’t enough empty space on the volume to satisfy the allocation request, PBAllocate allocates the rest of the space on the volume and returns dskFulErr as its function result. Note: Even if the total number of requested bytes is unavailable, PBAllocate will allocate whatever space, contiguous or not, is available. To force the allocation of the entire requested space as a contiguous piece, call PBAllocContig instead. Result codes noErr No error dskFulErr Disk full fLckdErr File locked fnOpnErr File not open ioErr I/O error rfNumErr Bad reference number vLckdErr Software volume lock wPrErr Hardware volume lock wrPermErr Read/write permission doesn’t allow writing æKY PBGetEOF æFp Files.p æT FUNCTION æD FUNCTION PBGetEOF(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetEOF(paramBlock,async); æRI II-112, IV-142 æC Trap macro _GetEOF Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word <-- 28 ioMisc long word PBGetEOF returns, in ioMisc, the logical end-of-file of the open file whose access path is specified by ioRefNum. Result codes noErr No error extFSErr External file system fnOpnErr File not open ioErr I/O error rfNumErr Bad reference number æKY PBSetEOF æFp Files.p æT FUNCTION æD FUNCTION PBSetEOF(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetEOF(paramBlock,async); æRI II-112, IV-142 æC Trap macro _SetEOF Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word --> 28 ioMisc long word PBSetEOF sets the logical end-of-file of the open file, whose access path is specified by ioRefNum, to ioMisc. If you attempt to set the logical end-of-file beyond the physical end-of-file, another allocation block is added to the file; if there isn’t enough space on the volume, no change is made, and PBSetEOF returns dskFulErr as its function result. If ioMisc is 0, all space occupied by the file on the volume is released. Result codes noErr No error dskFulErr Disk full extFSErr External file system fLckdErr File locked fnOpnErr File not open ioErr I/O error rfNumErr Bad reference number vLckdErr Software volume lock wPrErr Hardware volume lock wrPermErr Read/write permission doesn’t allow writing æKY PBGetFPos æFp Files.p æT FUNCTION æD FUNCTION PBGetFPos(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetFPos(paramBlock,async); æRI II-111, IV-141 æC Trap macro _GetFPos Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word <-- 36 ioReqCount long word <-- 40 ioActCount long word <-- 44 ioPosMode word <-- 46 ioPosOffset long word PBGetFPos returns, in ioPosOffset, the mark of the open file whose access path is specified by ioRefNum. It sets ioReqCount, ioActCount, and ioPosMode to 0. Result codes noErr No error extFSErr External file system fnOpnErr File not open gfpErr Error during GetFPos ioErr I/O error rfNumErr Bad reference number æKY PBSetFPos æFp Files.p æT FUNCTION æD FUNCTION PBSetFPos(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetFPos(paramBlock,async); æRI II-111, IV-141 æC Trap macro _SetFPos Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word --> 44 ioPosMode word <-> 46 ioPosOffset long word PBSetFPos sets the mark of the open file whose access path is specified by ioRefNum to the position specified by ioPosMode and ioPosOffset. The position at which the mark is actually set is returned in ioPosOffset. If you try to set the mark past the logical end-of-file, PBSetFPos moves the mark to the end-of-file and returns eofErr as its function result. Result codes noErr No error eofErr End-of-file extFSErr External file system fnOpnErr File not open ioErr I/O error posErr Attempt to position before start of file rfNumErr Bad reference number æKY PBFlushFile æFp Files.p æT FUNCTION æD FUNCTION PBFlushFile(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBFlushFile(paramBlock,async); æRI II-114, IV-144 æC Trap macro _FlushFile Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word PBFlushFile writes the contents of the access path buffer indicated by ioRefNum to the volume, and updates the file’s entry in the file directory (or in the file catalog, in the case of hierarchical volumes). Warning: Some information stored on the volume won’t be correct until PBFlushVol is called. Result codes noErr No error extFSErr External file system fnfErr File not found fnOpnErr File not open ioErr I/O error nsvErr No such volume rfNumErr Bad reference number æKY PBMountVol æFp Files.p æT FUNCTION æD FUNCTION PBMountVol(paramBlock: ParmBlkPtr): OSErr; æDT myVariable := PBMountVol(paramBlock); æMM æRT 134 æRI II-103, IV-128 æC »Accessing Volumes To get the volume reference number of a volume, given the path reference number of a file on that volume, both Pascal and assembly-language programmers can call the high-level File Manager function GetVRefNum. Assembly-language programmers may prefer calling the function GetFCBInfo (described below in the section “Data Structures in Memory”). FUNCTION PBMountVol (paramBlock: ParmBlkPtr) : OSErr; Trap macro _MountVol Parameter block <-- 16 ioResult word <-> 22 ioVRefNum word PBMountVol mounts the volume in the drive specified by ioVRefNum, and returns a volume reference number in ioVRefNum. If there are no volumes already mounted, this volume becomes the default volume. PBMountVol is always executed synchronously. Note: When mounting hierarchical volumes, PBMountVol opens two files needed for maintaining file directory and file mapping information. PBMountVol can fail if there are no access paths available for these two files; it will return tmfoErr as its function result. Result codes noErr No error badMDBErr Bad master directory block extFSErr External file system ioErr I/O error memFullErr Not enough room in heap zone noMacDskErr Not a Macintosh disk nsDrvErr No such drive paramErr Bad drive number tmfoErr Too many files open volOnLinErr Volume already on-line æKY PBUnmountVol æFp Files.p æT FUNCTION æD FUNCTION PBUnmountVol(paramBlock: ParmBlkPtr): OSErr; æDT myVariable := PBUnmountVol(paramBlock); æRI II-106, IV-134 æC Trap macro _UnmountVol Parameter block <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word PBUnmountVol unmounts the volume specified by ioNamePtr or ioVRefNum, by calling PBFlushVol to flush the volume, closing all open files on the volume, and releasing the memory used for the volume. PBUnmountVol is always executed synchronously. Warning: Don’t unmount the startup volume. Note: Unmounting a volume does not close working directories; to release the memory allocated to a working directory, call PBCloseWD. Result codes noErr No error bdNamErr Bad volume name extFSErr External file system ioErr I/O error nsDrvErr No such drive nsvErr No such volume paramErr No default volume æKY PBEject æFp Files.p æT FUNCTION æD FUNCTION PBEject(paramBlock: ParmBlkPtr): OSErr; æDT myVariable := PBEject(paramBlock); æMM æRI II-107, IV-135 æC Trap macro _Eject Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word PBEject flushes the volume specified by ioNamePtr or ioVRefNum, places it off-line, and then ejects the volume. Assembly-language note: You may invoke the macro _Eject asynchronously; the first part of the call is executed synchronously, and the actual ejection is executed asynchronously. Result codes noErr No error bdNamErr Bad volume name extFSErr External file system ioErr I/O error nsDrvErr No such drive nsvErr No such volume paramErr No default volume æKY PBOffLine æFp Files.p æT FUNCTION æD FUNCTION PBOffLine(paramBlock: ParmBlkPtr): OSErr; æDT myVariable := PBOffLine(paramBlock); æMM æRI II-106, IV-134 æC Trap macro _OffLine Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word PBOffLine places off-line the volume specified by ioNamePtr or ioVRefNum, by calling PBFlushVol to flush the volume and releasing all the memory used for the volume except for the volume control block. PBOffLine is always executed synchronously. Result codes noErr No error bdNamErr Bad volume name extFSErr External file system ioErr I/O error nsDrvErr No such drive nsvErr No such volume paramErr No default volume æKY AddDrive æFp Files.p æT PROCEDURE æD PROCEDURE AddDrive(drvrRefNum: INTEGER;drvNum: INTEGER;qEl: DrvQElPtr); æDT AddDrive(drvrRefNum,drvNum,qEl); æRT 36, 108 æRI N36, N108-1 æC æKY FSOpen æFp Files.p æT FUNCTION æD FUNCTION FSOpen(fileName: Str255;vRefNum: INTEGER;VAR refNum: INTEGER): OSErr; æDT myVariable := FSOpen(fileName,vRefNum,refNum); æRT 102 æRI II-91, IV-109, P-131, 171 æC [Not in ROM] FSOpen creates an access path to the file having the name fileName on the volume specified by vRefNum. A path reference number is returned in refNum. The access path’s read/write permission is set to whatever the file’s open permission allows. Note: There’s no guarantee that any bytes have been written until FlushVol is called. Result codes noErr No error bdNamErr Bad file name extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing tmfoErr Too many files open æKY FSClose æFp Files.p æT FUNCTION æD FUNCTION FSClose(refNum: INTEGER): OSErr; æDT myVariable := FSClose(refNum); æRT 102 æRI II-94, IV-112, P-132, 133, 171 æC [Not in ROM] FSClose removes the access path specified by refNum, writes the contents of the volume buffer to the volume, and updates the file’s entry in the file directory. Note: There’s no guarantee that any bytes have been written until FlushVol is called. Result codes noErr No error extFSErr External file system fnfErr File not found fnOpnErr File not open ioErr I/O error nsvErr No such volume rfNumErr Bad reference number æKY FSRead æFp Files.p æT FUNCTION æD FUNCTION FSRead(refNum: INTEGER;VAR count: LONGINT;buffPtr: Ptr): OSErr; æDT myVariable := FSRead(refNum,count,buffPtr); æRI IV-109, P-131, 171 æC [Not in ROM] FSRead attempts to read the number of bytes specified by the count parameter from the open file whose access path is specified by refNum, and transfer them to the data buffer pointed to by buffPtr. The read operation begins at the current mark, so you might want to precede this with a call to SetFPos. If you try to read past the logical end-of-file, FSRead moves the mark to the end-of-file and returns eofErr as its function result. After the read is completed, the number of bytes actually read is returned in the count parameter. Result codes noErr No error eofErr End-of-file extFSErr External file system fnOpnErr File not open ioErr I/O error paramErr Negative count rfNumErr Bad reference number æKY FSWrite æFp Files.p æT FUNCTION æD FUNCTION FSWrite(refNum: INTEGER;VAR count: LONGINT;buffPtr: Ptr): OSErr; æDT myVariable := FSWrite(refNum,count,buffPtr); æRI IV-110, P-132, 171 æC [Not in ROM] FSWrite takes the number of bytes specified by the count parameter from the buffer pointed to by buffPtr and attempts to write them to the open file whose access path is specified by refNum. The write operation begins at the current mark, so you might want to precede this with a call to SetFPos. After the write is completed, the number of bytes actually written is returned in the count parameter. Result codes noErr No error dskFulErr Disk full fLckdErr File locked fnOpnErr File not open ioErr I/O error paramErr Negative count rfNumErr Bad reference number vLckdErr Software volume lock wPrErr Hardware volume lock wrPermErr Read/write permission doesn’t allow writing æKY GetVInfo æFp Files.p æT FUNCTION æD FUNCTION GetVInfo(drvNum: INTEGER;volName: StringPtr;VAR vRefNum: INTEGER; VAR freeBytes: LONGINT): OSErr; æDT myVariable := GetVInfo(drvNum,volName,vRefNum,freeBytes); æRT 157 æRI II-89, IV-107, N157, low-level II-104, IV-129 æC »Accessing Volumes •••Refer to Technical Note #24:••• FUNCTION GetVInfo (drvNum: INTEGER; volName: StringPtr; VAR vRefNum: INTEGER; VAR freeBytes: LONGINT) : OSErr; [Not in ROM] •••Refer to Technical Note #157:••• GetVInfo returns the name, reference number, and available space (in bytes), in volName, vRefNum, and freeBytes, for the volume in the drive specified by drvNum. Result codes noErr No error nsvErr No default volume paramErr Bad drive number æKY GetFInfo æFp Files.p æT FUNCTION æD FUNCTION GetFInfo(fileName: Str255;vRefNum: INTEGER;VAR fndrInfo: FInfo): OSErr; æDT myVariable := GetFInfo(fileName,vRefNum,fndrInfo); æRI II-95, IV-113 æC [Not in ROM] For the file having the name fileName on the specified volume, GetFInfo returns information used by the Finder in fndrInfo (see the section “Information Used by the Finder”). Result codes noErr No error bdNamErr Bad file name extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume paramErr No default volume æKY GetVol æFp Files.p æT FUNCTION æD FUNCTION GetVol(volName: StringPtr;VAR vRefNum: INTEGER): OSErr; æDT myVariable := GetVol(volName,vRefNum); æRT 77,140 æRI N77-2, N140 high-level II-89, IV-107 low-level II-104, IV-131 æC [Not in ROM] GetVol returns the name of the default volume in volName and its volume reference number in vRefNum. Result codes noErr No error nsvErr No such volume æKY SetVol æFp Files.p æT FUNCTION æD FUNCTION SetVol(volName: StringPtr;vRefNum: INTEGER): OSErr; æDT myVariable := SetVol(volName,vRefNum); æRI II-89, IV-107 low-level II-105, IV-132 æC [Not in ROM] SetVol sets the default volume to the mounted volume specified by volName or vRefNum. Result codes noErr No error bdNamErr Bad volume name nsvErr No such volume paramErr No default volume æKY UnmountVol æFp Files.p æT FUNCTION æD FUNCTION UnmountVol(volName: StringPtr;vRefNum: INTEGER): OSErr; æDT myVariable := UnmountVol(volName,vRefNum); æRT 180 æRI II-90, IV-108 low-level II-106, IV-134 æC [Not in ROM] UnmountVol unmounts the volume specified by volName or vRefNum, by calling FlushVol to flush the volume buffer, closing all open files on the volume, and releasing the memory used for the volume. Warning: Don’t unmount the startup volume. Result codes noErr No error bdNamErr Bad volume name extFSErr External file system ioErr I/O error nsDrvErr No such drive nsvErr No such volume paramErr No default volume æKY Eject æFp Files.p æT FUNCTION æD FUNCTION Eject(volName: StringPtr;vRefNum: INTEGER): OSErr; æDT myVariable := Eject(volName,vRefNum); æMM æRI II-90, IV-108 low-level II-107, IV-135 æC [Not in ROM] Eject flushes the volume specified by volName or vRefNum, places it off-line, and then ejects the volume. Result codes noErr No error bdNamErr Bad volume name extFSErr External file system ioErr I/O error nsDrvErr No such drive nsvErr No such volume paramErr No default volume paramErr No default volume æKY FlushVol æFp Files.p æT FUNCTION æD FUNCTION FlushVol(volName: StringPtr;vRefNum: INTEGER): OSErr; æDT myVariable := FlushVol(volName,vRefNum); æMM æRI P-132, 133 high-level II-89, IV-108 low-level II-105, IV-133 æC [Not in ROM] On the volume specified by volName or vRefNum, FlushVol writes the contents of the associated volume buffer and descriptive information about the volume (if they’ve changed since the last time FlushVol was called). Result codes noErr No error bdNamErr Bad volume name extFSErr External file system ioErr I/O error nsDrvErr No such drive nsvErr No such volume paramErr No default volume æKY Create æFp Files.p æT FUNCTION æD FUNCTION Create(fileName: Str255;vRefNum: INTEGER;creator: OSType;fileType: OSType): OSErr; æDT myVariable := Create(fileName,vRefNum,creator,fileType); æRI II-90, IV-112 low-level II-107, IV-145 æC [Not in ROM] Create creates a new file (both forks) with the specified name, file type, and creator on the specified volume. (File type and creator are discussed in the Finder Interface chapter.) The new file is unlocked and empty. The date and time of its creation and last modification are set to the current date and time. Result codes noErr No error bdNamErr Bad file name dupFNErr Duplicate file name and version dirFulErr File directory full extFSErr External file system ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY FSDelete æFp Files.p æT FUNCTION æD FUNCTION FSDelete(fileName: Str255;vRefNum: INTEGER): OSErr; æDT myVariable := FSDelete(fileName,vRefNum); æRI II-97, IV-113 æC [Not in ROM] FSDelete removes the closed file having the name fileName from the specified volume. Note: This function will delete both forks of a file. Result codes noErr No error bdNamErr Bad file name extFSErr External file system fBsyErr File busy fLckdErr File locked fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY OpenRF æFp Files.p æT FUNCTION æD FUNCTION OpenRF(fileName: Str255;vRefNum: INTEGER;VAR refNum: INTEGER): OSErr; æDT myVariable := OpenRF(fileName,vRefNum,refNum); æRT 74 æRI II-91, IV-109 low-level II-109, IV-137 æC [Not in ROM] OpenRF is similar to FSOpen; the only difference is that OpenRF opens the resource fork of the specified file rather than the data fork. A path reference number is returned in refNum. The access path’s read/write permission is set to whatever the file’s open permission allows. Note: Normally you should access a file’s resource fork through the routines of the Resource Manager rather than the File Manager. OpenRF doesn’t read the resource map into memory; it’s really only useful for block-level operations such as copying files. Result codes noErr No error bdNamErr Bad file name extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing tmfoErr Too many files open æKY Rename æFp Files.p æT FUNCTION æD FUNCTION Rename(oldName: Str255;vRefNum: INTEGER;newName: Str255): OSErr; æDT myVariable := Rename(oldName,vRefNum,newName); æRI II-96, IV-114 low-level II-118, IV-153 æC [Not in ROM] Given a file name in oldName, Rename changes the name of the file to newName. Access paths currently in use aren’t affected. Given a volume name in oldName or a volume reference number in vRefNum, Rename changes the name of the specified volume to newName. Warning: If you’re renaming a volume, be sure that both names end with a colon. Result codes noErr No error bdNamErr Bad file name dirFulErr Directory full dupFNErr Duplicate file name extFSErr External file system fLckdErr File locked fnfErr File not found fsRnErr Problem during rename ioErr I/O error nsvErr No such volume paramErr No default volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY SetFInfo æFp Files.p æT FUNCTION æD FUNCTION SetFInfo(fileName: Str255;vRefNum: INTEGER;fndrInfo: FInfo): OSErr; æDT myVariable := SetFInfo(fileName,vRefNum,fndrInfo); æRI II-95, IV-114 æC [Not in ROM] For the file having the name fileName on the specified volume, SetFInfo sets information used by the Finder to fndrInfo (see the section “Information Used by the Finder”). Result codes noErr No error extFSErr External file system fLckdErr File locked fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY SetFLock æFp Files.p æT FUNCTION æD FUNCTION SetFLock(fileName: Str255;vRefNum: INTEGER): OSErr; æDT myVariable := SetFLock(fileName,vRefNum); æRI II-95, IV-114 æC [Not in ROM] SetFLock locks the file having the name fileName on the specified volume. Access paths currently in use aren’t affected. Result codes noErr No error extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY RstFLock æFp Files.p æT FUNCTION æD FUNCTION RstFLock(fileName: Str255;vRefNum: INTEGER): OSErr; æDT myVariable := RstFLock(fileName,vRefNum); æRI II-96, IV-114 æC [Not in ROM] RstFLock unlocks the file having the name fileName on the specified volume. Access paths currently in use aren’t affected. Result codes noErr No error extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY Allocate æFp Files.p æT FUNCTION æD FUNCTION Allocate(refNum: INTEGER;VAR count: LONGINT): OSErr; æDT myVariable := Allocate(refNum,count); æRI IV-143 æC [Not in ROM] Allocate adds the number of bytes specified by the count parameter to the open file whose access path is specified by refNum, and sets the physical end-of-file to one byte beyond the last block allocated. The number of bytes actually allocated is rounded up to the nearest multiple of the allocation block size, and returned in the count parameter. If there isn’t enough empty space on the volume to satisfy the allocation request, Allocate allocates the rest of the space on the volume and returns dskFulErr as its function result. Result codes noErr No error dskFulErr Disk full fLckdErr File locked fnOpnErr File not open ioErr I/O error rfNumErr Bad reference number vLckdErr Software volume lock wPrErr Hardware volume lock wrPermErr Read/write permission doesn’t allow writing æKY GetEOF æFp Files.p æT FUNCTION æD FUNCTION GetEOF(refNum: INTEGER;VAR logEOF: LONGINT): OSErr; æDT myVariable := GetEOF(refNum,logEOF); æRI P-132, 172 high-level II-93, IV-111 low-level II-112, IV-142 æC [Not in ROM] GetEOF returns, in logEOF, the logical end-of-file of the open file whose access path is specified by refNum. Result codes noErr No error extFSErr External file system fnOpnErr File not open ioErr I/O error rfNumErr Bad reference number æKY SetEOF æFp Files.p æT FUNCTION æD FUNCTION SetEOF(refNum: INTEGER;logEOF: LONGINT): OSErr; æDT myVariable := SetEOF(refNum,logEOF); æRI P-132, 180 high-level II-93, IV-111 low-level II-112, IV-142 æC [Not in ROM] SetEOF sets the logical end-of-file of the open file whose access path is specified by refNum to the position specified by logEOF. If you attempt to set the logical end-of-file beyond the physical end-of-file, the physical end-of-file is set to one byte beyond the end of the next free allocation block; if there isn’t enough space on the volume, no change is made, and SetEOF returns dskFulErr as its function result. If logEOF is 0, all space occupied by the file on the volume is released. Result codes noErr No error dskFulErr Disk full extFSErr External file system fLckdErr File locked fnOpnErr File not open ioErr I/O error rfNumErr Bad reference number vLckdErr Software volume lock wPrErr Hardware volume lock wrPermErr Read/write permission doesn’t allow writing æKY GetFPos æFp Files.p æT FUNCTION æD FUNCTION GetFPos(refNum: INTEGER;VAR filePos: LONGINT): OSErr; æDT myVariable := GetFPos(refNum,filePos); æRI II-92, IV-110 low-level II-111, IV-141 æC [Not in ROM] GetFPos returns, in filePos, the mark of the open file whose access path is specified by refNum. Result codes noErr No error extFSErr External file system fnOpnErr File not open ioErr I/O error rfNumErr Bad reference number æKY SetFPos æFp Files.p æT FUNCTION æD FUNCTION SetFPos(refNum: INTEGER;posMode: INTEGER;posOff: LONGINT): OSErr; æDT myVariable := SetFPos(refNum,posMode,posOff); æRI P-131, 132, 180 high-level II-93, IV-110 low-level II-111, IV-141 æC [Not in ROM] SetFPos sets the mark of the open file whose access path is specified by refNum to the position specified by posMode and posOff (except when posMode is equal to fsAtMark, in which case posOff is ignored). PosMode indicates how to position the mark; it must contain one of the following values: CONST fsAtMark = 0; {at current mark} fsFromStart = 1; {set mark relative to beginning of file} fsFromLEOF = 2; {set mark relative to logical end-of-file} fsFromMark = 3; {set mark relative to current mark} If you specify fsAtMark, posOffset is ignored and the mark is left wherever it’s currently positioned. If you choose to set the mark (relative to either the beginning of the file, the logical end-of-file, or the current mark), posOffset specifies the byte offset from the chosen point (either positive or negative) where the mark should be set. If you try to set the mark past the logical end-of-file, SetFPos moves the mark to the end-of-file and returns eofErr as its function result. Result codes noErr No error eofErr End-of-file extFSErr External file system fnOpnErr File not open ioErr I/O error posErr Attempt to position before start of file rfNumErr Bad reference number æKY GetVRefNum æFp Files.p æT FUNCTION æD FUNCTION GetVRefNum(fileRefNum: INTEGER;VAR vRefNum: INTEGER): OSErr; æDT myVariable := GetVRefNum(fileRefNum,vRefNum); æRI II-89, IV-107 æC [Not in ROM] Given a path reference number in pathRefNum, GetVRefNum returns the volume reference number in vRefNum. Result codes noErr No error rfNumErr Bad reference number æKY PBOpenDF æFp Files.p æT FUNCTION æD FUNCTION PBOpenDF(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBOpenDF(paramBlock,async); æRI VI æC OpenDF creates an access path to the data fork of a file. It is almost identical to PBFSOpen, which is documented in the File Manager chapter of Volume IV. The difference is that PBFSOpen can open both files and devices, but PBOpenDF can open only files. Using OpenDF instead of FSOpen when your application is opening a file prevents naming conflicts or ambiguities. æKY PBOpenWD æFp Files.p æT FUNCTION æD FUNCTION PBOpenWD(paramBlock: WDPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBOpenWD(paramBlock,async); æRT 77, 190 æRI IV-158, N77-1 æC Trap macro _OpenWD Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer <-> 22 ioVRefNum word --> 28 ioWDProcID long word --> 48 ioWDDirID long word PBOpenWD takes the directory specified by ioVRefNum, ioWDDirID, and ioWDProcID and makes it a working directory. (You can also specify the directory using a combination of partial pathname and directory ID.) It returns a working directory reference number in ioVRefNum that can be used in subsequent calls. If a given directory has already been made a working directory using the same ioWDProcID, no new working directory will be opened; instead, the existing working directory reference number will be returned. If a given directory was already made a working directory using a different ioWDProcID, a new working directory reference number is returned. Result codes noErr No error tmwdoErr Too many working directories open æKY PBCloseWD æFp Files.p æT FUNCTION æD FUNCTION PBCloseWD(paramBlock: WDPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBCloseWD(paramBlock,async); æRI IV-158 æC Trap macro _CloseWD Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 22 ioVRefNum word PBCloseWD releases the working directory whose working directory reference number is specified in ioVRefNum. Note: If a volume reference number is specified in ioVRefNum, PBCloseWD does nothing. Result codes noErr No error nsvErr No such volume æKY PBHSetVol æFp Files.p æT FUNCTION æD FUNCTION PBHSetVol(paramBlock: WDPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHSetVol(paramBlock,async); æRT 140 æRI IV-133, N140 æC •••Refer to Technical Note #140:••• Trap macro _HSetVol Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 48 ioWDDirID long word PBHSetVol sets both the default volume and the default directory. The default directory to be used can be specified by either a volume reference number or a working directory reference number in ioVRefNum, a directory ID in ioWDDirID, or a pointer to a pathname (possibly NIL) in ioNamePtr. Note: Both the default volume and the default directory are used in calls made with no volume name and a volume reference number of zero. Result codes noErr No error nsvErr No default volume æKY PBHGetVol æFp Files.p æT FUNCTION æD FUNCTION PBHGetVol(paramBlock: WDPBPtr;async: BOOLEAN): OSErr; { Trap macro _HGetVol Parameter block —> 12 ioCompletion pointer <— 16 ioResult word <— 18 ioNamePtr pointer <— 22 ioVRefNum word <— 28 ioWDProcID long word <— 32 ioWDVRefNum word <— 48 ioWDDirID long word PBHGetVol returns the default volume and directory last set by either a PBSetVol or a PBHSetVol call. The reference number of the default volume is returned in ioVRefNum. Warning: IOVRefNum will return a working directory reference number (instead of the volume reference number) if, in the last call to PBSetVol or PBHSetVol, a working directory reference number was passed in this field. The volume reference number of the volume on which the default directory exists is returned in ioWDVRefNum. The directory ID of the default directory is returned in ioWDDirID. Result codes noErr No error nsvErr No default volume } æDT myVariable := PBHGetVol(paramBlock,async); æRI IV-132 æC Trap macro _HGetVol Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-- 18 ioNamePtr pointer <-- 22 ioVRefNum word <-- 28 ioWDProcID long word <-- 32 ioWDVRefNum word <-- 48 ioWDDirID long word PBHGetVol returns the default volume and directory last set by either a PBSetVol or a PBHSetVol call. The reference number of the default volume is returned in ioVRefNum. Warning: IOVRefNum will return a working directory reference number (instead of the volume reference number) if, in the last call to PBSetVol or PBHSetVol, a working directory reference number was passed in this field. The volume reference number of the volume on which the default directory exists is returned in ioWDVRefNum. The directory ID of the default directory is returned in ioWDDirID. Result codes noErr No error nsvErr No default volume æKY PBCatMove æFp Files.p æT FUNCTION æD FUNCTION PBCatMove(paramBlock: CMovePBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBCatMove(paramBlock,async); æRI IV-157, VI æC Some existing HFS functions now support file IDs as appropriate, but their interface remains stable. This section describes how they accommodate file IDs. FUNCTION PBCatMove (paramBlock: HParamBlkPtr, async: Boolean) : OSErr; If a file ID exists for the file being moved, the file ID remains with the file. •••Refer to Technical Note #226:••• Trap macro _CatMove Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 28 ioNewName pointer --> 36 ioNewDirID long word --> 48 ioDirID long word PBCatMove moves files or directories from one directory to another. The name of the file or directory to be moved is pointed to by ioNamePtr; ioVRefNum contains either the volume reference number or working directory reference number. A directory ID can be specified in ioDirID. The name and directory ID of the directory to which the file or directory is to be moved are specified by ioNewName and ioNewDirID. PBCatMove is strictly a file catalog operation; it does not actually change the location of the file or directory on the disk. PBCatMove cannot move a file or directory to another volume (that is, ioVRefNum is used in specifying both the source and the destination). It also cannot be used to rename files or directories; for that, use PBHRename. Result codes noErr No error badMovErr Attempt to move into offspring bdNamErr Bad file name or attempt to move into a file dupFNErr Duplicate file name and version fnfErr File not found ioErr I/O error nsvErr No such volume paramErr No default volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBDirCreate æFp Files.p æT FUNCTION æD FUNCTION PBDirCreate(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDirCreate(paramBlock,async); æRI IV-146 æC Trap macro _DirCreate Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-> 18 ioNamePtr pointer --> 22 ioVRefNum word <-> 48 ioDirID long word PBDirCreate is identical to PBHCreate except that it creates a new directory instead of a file. You can specify the parent of the directory to be created in ioDirID; if it’s 0, the new directory will be placed in the root directory. The directory ID of the new directory is returned in ioDirID. Warning: PBDirCreate operates only with the hierarchical version of the File Manager; if used on a Macintosh equipped only with the 64K ROM version of the File Manager, it will generate a system error. Result codes noErr No error bdNamErr Bad file name dupFNErr Duplicate file name and version dirFulErr File directory full dirNFErr Directory not found or incomplete pathname extFSErr External file system ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBGetWDInfo æFp Files.p æT FUNCTION æD FUNCTION PBGetWDInfo(paramBlock: WDPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetWDInfo(paramBlock,async); æRT 77, 190 æRI IV-159, N77-5 æC Trap macro _GetWDInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-- 18 ioNamePtr pointer <-> 22 ioVRefNum word --> 26 ioWDIndex word <-> 28 ioWDProcID long word <-> 32 ioWDVRefNum word <-- 48 ioWDDirID long word PBGetWDInfo returns information about the specified working directory. The working directory can be specified either by its working directory reference number in ioVRefNum (in which case ioWDIndex should be 0), or by its index number in ioWDIndex. In the latter case, if ioVRefNum is nonzero, it’s interpreted as a volume specification (volume reference number or drive number), and only working directories on that volume are indexed. IOWDVRefNum always returns the volume reference number. IOVRefNum returns a working directory reference number when a working directory reference number is passed in that field; otherwise, it returns a volume reference number. The volume name is returned in ioNamePtr. If IOWDProcID is nonzero, only working directories with that identifier are indexed; otherwise all working directories are indexed. Result codes noErr No error nsvErr No such volume æKY PBGetFCBInfo æFp Files.p æT FUNCTION æD FUNCTION PBGetFCBInfo(paramBlock: FCBPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetFCBInfo(paramBlock,async); æRT 87 æRI IV-179, N87-1 æC Trap macro _GetFCBInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-- 18 ioNamePtr pointer <-> 22 ioVRefNum word <-> 24 ioRefNum word --> 28 ioFCBIndx long word <-- 32 ioFCBFlNm long word <-- 36 ioFCBFlags word <-- 38 ioFCBStBlk word <-- 40 ioFCBEOF long word <-- 44 ioFCBPLen long word <-- 48 ioFCBCrPs long word <-- 52 ioFCBVRefNum word <-- 54 ioFCBClpSiz long word <-- 58 ioFCBParID long word PBGetFCBInfo returns information about the specified open file. If ioFCBIndx is positive, the File Manager returns information about the file whose file number is ioFCBIndx on the volume specified by ioVRefNum (which may contain a drive number, volume reference number, or working directory reference number). If ioVRefNum is 0, all open files are indexed; otherwise, only open files on the specified volume are indexed. If ioFCBIndx is 0, the File Manager returns information about the file whose access path is specified by ioRefNum. Assembly-language note: The global variable FCBSPtr points to the length word of the file-control-block buffer. Each file control block contains 94 bytes of information about an access path; Figure 28 shows its structure (using the assembly-language offsets). •••Refer to Figure 28:••• Figure 28–A File Control Block 64K ROM note: The structure of a file control block in the 64K ROM version of the File Manager is a subset of the above structure. The old file control block contained only the fields up to and including fcbFlPos. FCBMdRByt (which corresponds to ioFCBFlags in the parameter block for PBGetFCBInfo) contains flags that describe the status of the file, as follows: Bit Meaning 0 Set if data can be written to the file 1 Set if the entry describes a resource fork 7 Set if the file has been changed since it was last flushed Warning: The size and structure of a file control block may be different in future versions of Macintosh system software. æKY PBGetCatInfo æFp Files.p æT FUNCTION æD FUNCTION PBGetCatInfo(paramBlock: CInfoPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetCatInfo(paramBlock,async); æRT 68,69 æRI IV-155, V-391, N68-1, N69, VI æC Some existing HFS functions now support file IDs as appropriate, but their interface remains stable. This section describes how they accommodate file IDs. FUNCTION PBGetCatInfo (paramBlock: HParamBlkPtr, async: Boolean) : OSErr; You can use PBGetCatInfo to determine whether a file has a file ID. The value of the file ID is returned in ioDirID. Because that parameter could also represent a directory ID, call PBResolveFileID to see if the value is a real file ID. If you want to both determine whether a file ID exists for a file and create one if it doesn’t, use PBCreateFileID, which will either create a file ID or return fidExists. •••Refer to Technical Note #69:••• Trap macro _GetCatInfo Parameter block Files: Directories: --> 12 ioCompletion pointer --> 12 ioCompletion pointer <-- 16 ioResult word <-- 16 ioResult word <-> 18 ioNamePtr pointer <-> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 22 ioVRefNum word <-- 24 ioFRefNum word <-- 24 ioFRefNum word --> 28 ioFDirIndex word --> 28 ioFDirIndex word <-- 30 ioFlAttrib byte <-- 30 ioFlAttrib byte <-- 31 ioACUser byte access rights for directory only <-- 32 ioFlFndrInfo 16 bytes <-- 32 ioDrUsrWds 16 bytes <-> 48 ioDirID long word <-> 48 ioDrDirID long word <-- 52 ioFlStBlk word <-- 52 ioDrNmFls word <-- 54 ioFlLgLen long word <-- 58 ioFlPyLen long word <-- 62 ioFlRStBlk word <-- 64 ioFlRLgLen long word <-- 68 ioFlRPyLen long word <-- 72 ioFlCrDat long word <-- 72 ioDrCrDat long word <-- 76 ioFlMdDat long word <-- 76 ioDrMdDat long word <-- 80 ioFlBkDat long word <-- 80 ioDrBkDat long word <-- 84 ioFlXFndrInfo 16 bytes <-- 84 ioDrFndrInfo 16 bytes <-- 100 ioFlParID long word <-- 100 ioDrParID long word <-- 104 ioFlClpSiz long word PBGetCatInfo gets information about the files and directories in a file catalog. To determine whether the information is for a file or a directory, test bit 4 of ioFlAttrib, as described in the section “CInfoPBRec”. The information that’s returned for files is shown in the left column, and the corresponding information for directories is shown in the right column. If ioFDirIndex is positive, the File Manager returns information about the file or directory whose directory index is ioFDirIndex in the directory specified by ioVRefNum (this will be the root directory if a volume reference number is provided). If ioFDirIndex is 0, the File Manager returns information about the file or directory specified by ioNamePtr, in the directory specified by ioVRefNum (again, this will be the root directory if a volume reference number is provided). If ioFDirIndex is negative, the File Manager ignores ioNamePtr and returns information about the directory specified by ioDirID. With files, PBGetCatInfo is similar to PBHGetFileInfo but returns some additional information. If the file is open, the reference number of the first access path found is returned in ioFRefNum, and the name of the file is returned in ioNamePtr (unless ioNamePtr is NIL). For server volume directories, in addition to the normal return parameters the ioACUser field returns the user’s access rights in the following format: Bit 7 if set, user is not the owner of the directory. if clear, user is the owner of the directory. 6–3 Reserved; this is returned set to zero. 2 If set, user does not have Make Changes privileges to the directory. If clear, user has Make Changes privileges to the directory. 1 If set, user does not have See Files privileges to the directory. If clear, user has See Files privileges to the directory. 0 If set, user does not have See Folders privileges to the directory. If clear, user has See Folders privileges to the directory. For example, if ioACUser returns zero for a given server volume directory, you know that the user is the owner of the directory and has complete privileges to it. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume paramErr No default volume æKY PBSetCatInfo æFp Files.p æT FUNCTION æD FUNCTION PBSetCatInfo(paramBlock: CInfoPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetCatInfo(paramBlock,async); æRI IV-156 æC Trap macro _SetCatInfo Parameter block Files: Directories: --> 12 ioCompletion pointer --> 12 ioCompletion pointer <-- 16 ioResult word <-- 16 ioResult word <-> 18 ioNamePtr pointer <-> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 22 ioVRefNum word --> 30 ioFlAttrib byte --> 30 ioFlAttrib byte --> 32 ioFlFndrInfo 16 bytes --> 32 ioDrUsrWds 16 bytes --> 48 ioDirID long word --> 48 ioDrDirID long word --> 72 ioFlCrDat long word --> 72 ioDrCrDat long word --> 76 ioFlMdDat long word --> 76 ioDrMdDat long word --> 80 ioFlBkDat long word --> 80 ioDrBkDat long word --> 84 ioFlXFndrInfo 16 bytes --> 84 ioDrFndrInfo 16 bytes --> 104 ioFlClpSiz long word PBSetCatInfo sets information about the files and directories in a catalog. With files, it’s similar to PBHSetFileInfo but lets you set some additional information. The information that can be set for files is shown in the left column, and the corresponding information for directories is shown in the right column. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume paramErr No default volume æKY PBAllocContig æFp Files.p æT FUNCTION æD FUNCTION PBAllocContig(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBAllocContig(paramBlock,async); æRI IV-143 æC Trap macro _AllocContig Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word --> 36 ioReqCount long word <-- 40 ioActCount long word PBAllocContig is identical to PBAllocate except that if there isn’t enough contiguous empty space on the volume to satisfy the allocation request, PBAllocContig will do nothing and will return dskFulErr as its function result. If you want to allocate whatever space is available, even when the entire request cannot be filled as a contiguous piece, call PBAllocate instead. Result codes noErr No error dskFulErr Disk full fLckdErr File locked fnOpnErr File not open ioErr I/O error rfNumErr Bad reference number vLckdErr Software volume lock wPrErr Hardware volume lock wrPermErr Read/write permission doesn’t allow writing æKY PBLockRange æFp Files.p æT FUNCTION æD FUNCTION PBLockRange(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBLockRange(paramBlock,async); æRT 186 æRI IV-138 æC •••Refer to Technical Note #186:••• Trap macro _LockRng Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word --> 36 ioReqCount long word --> 44 ioPosMode word --> 46 ioPosOffset long word On a file opened with a shared read/write permission, PBLockRange is used in conjunction with PBRead and PBWrite to lock a certain portion of the file. PBLockRange uses the same parameters as both PBRead and PBWrite; by calling it immediately before PBRead, you can use the information present in the parameter block for the PBRead call. When you’re finished with the data (typically after a call to PBWrite), be sure to call PBUnlockRange to free up that portion of the file for subsequent PBRead calls. Warning: PBLockRange operates only with the hierarchical version of the File Manager; if used on a Macintosh equipped only with the 64K ROM version of the File Manager, it will generate a system error. Result codes noErr No error eofErr End-of-file extFSErr External file system fnOpnErr File not open ioErr I/O error paramErr Negative ioReqCount rfNumErr Bad reference number æKY PBUnlockRange æFp Files.p æT FUNCTION æD FUNCTION PBUnlockRange(paramBlock: ParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBUnlockRange(paramBlock,async); æRT 186 æRI IV-139 æC Trap macro _UnlockRng Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 24 ioRefNum word --> 36 ioReqCount long word --> 44 ioPosMode word --> 46 ioPosOffset long word PBUnlockRange is used in conjunction with PBRead and PBWrite to unlock a certain portion of a file that you locked with PBLockRange. Warning: PBUnlockRange operates only with the hierarchical version of the File Manager; if used on a Macintosh equipped only with the 64K ROM version of the File Manager, it will generate a system error. Result codes noErr No error eofErr End-of-file extFSErr External file system fnOpnErr File not open ioErr I/O error paramErr Negative ioReqCount rfNumErr Bad reference number æKY PBSetVInfo æFp Files.p æT FUNCTION æD FUNCTION PBSetVInfo(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetVInfo(paramBlock,async); æRT 204 æRI IV-131 æC •••Refer to Technical Note #204:••• Trap macro _SetVolInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 30 ioVCrDate long word --> 34 ioVLsMod long word --> 38 ioVAtrb word --> 52 ioVClpSiz long word --> 72 ioVBkUp long word --> 76 ioVSeqNum word --> 90 ioVFndrInfo 32 bytes PBSetVInfo lets you modify information about volumes. A pointer to a new name for the volume can be specified in ioNamePtr. The date and time of the volume’s creation and modification can be set with ioVCrDate and ioVLsMod respectively. Only bit 15 of ioVAtrb can be changed; setting it locks the volume. Note: The volume cannot be specified by name; you must use either the volume reference number or the drive number. Warning: PBSetVInfo operates only with the hierarchical version of the File Manager; if used on a Macintosh equipped only with the 64K ROM version of the File Manager, it will generate a system error. Result codes noErr No error nsvErr No such volume paramErr No default volume æKY PBHGetVInfo æFp Files.p æT FUNCTION æD FUNCTION PBHGetVInfo(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHGetVInfo(paramBlock,async); æRT 24, 66, 67, 77, 106, 157 æRI IV-130, N66-1, N67-1, N77-5 æC Trap macro _HGetVInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-> 18 ioNamePtr pointer <-> 22 ioVRefNum word --> 28 ioVolIndex word <-- 30 ioVCrDate long word <-- 34 ioVLsMod long word <-- 38 ioVAtrb word <-- 40 ioVNmFls word <-- 42 ioVBitMap word <-- 44 ioVAllocPtr word <-- 46 ioVNmAlBlks word <-- 48 ioVAlBlkSiz long word <-- 52 ioVClpSiz long word <-- 56 ioAlBlSt word <-- 58 ioVNxtFNum long word <-- 62 ioVFrBlk word <-- 64 ioVSigWord word <-- 66 ioVDrvInfo word <-- 68 ioVDRefNum word <-- 70 ioVFSID word <-- 72 ioVBkUp long word <-- 76 ioVSeqNum word <-- 78 ioVWrCnt long word <-- 82 ioVFilCnt long word <-- 86 ioVDirCnt long word <-- 90 ioVFndrInfo 32 bytes PBHGetVInfo is similar in function to PBGetVInfo but returns a larger parameter block. In addition, PBHGetVInfo always returns the volume reference number in ioVRefNum (regardless of what was passed in). Also, ioVNmAlBlks and ioVFrBlks are not clipped as they are by PBGetVInfo. Result codes noErr No error nsvErr No such volume paramErr No default volume æKY PBHOpen æFp Files.p æT FUNCTION æD FUNCTION PBHOpen(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; { Trap macro _HOpen Parameter block —> 12 ioCompletion pointer <— 16 ioResult word —> 18 ioNamePtr pointer —> 22 ioVRefNum word <— 24 ioRefNum word —> 27 ioPermssn byte —> 28 ioMisc pointer —> 48 ioDirID long word PBHOpen is identical to PBOpen except that it accepts a directory ID in ioDirID. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing permErr Attempt to open locked file for writing tmfoErr Too many files open } æDT myVariable := PBHOpen(paramBlock,async); æRT 204 æRI IV-136 æC Trap macro _HOpen Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word <-- 24 ioRefNum word --> 27 ioPermssn byte --> 28 ioMisc pointer --> 48 ioDirID long word PBHOpen is identical to PBOpen except that it accepts a directory ID in ioDirID. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing permErr Attempt to open locked file for writing tmfoErr Too many files open æKY PBHOpenRF æFp Files.p æT FUNCTION æD FUNCTION PBHOpenRF(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; { Trap macro _HOpenRF Parameter block —> 12 ioCompletion pointer <— 16 ioResult word —> 18 ioNamePtr pointer —> 22 ioVRefNum word <— 24 ioRefNum word —> 27 ioPermssn byte —> 28 ioMisc pointer —> 48 ioDirID long word PBHOpenRF is identical to PBOpenRF except that it accepts a directory ID in ioDirID. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing permErr Attempt to open locked file for writing tmfoErr Too many files open } æDT myVariable := PBHOpenRF(paramBlock,async); æRI IV-137 æC Trap macro _HOpenRF Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word <-- 24 ioRefNum word --> 27 ioPermssn byte --> 28 ioMisc pointer --> 48 ioDirID long word PBHOpenRF is identical to PBOpenRF except that it accepts a directory ID in ioDirID. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing permErr Attempt to open locked file for writing tmfoErr Too many files open æKY PBHOpenDF æFp Files.p æT FUNCTION æD FUNCTION PBHOpenDF(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHOpenDF(paramBlock,async); æRI IV-137, VI æC PBHOpenDF creates an access path to the data fork of a file. It is an HFS version of PBOpenDF. Trap macro _HOpenRF Parameter block —> 12 ioCompletion pointer <— 16 ioResult word —> 18 ioNamePtr pointer —> 22 ioVRefNum word <— 24 ioRefNum word —> 27 ioPermssn byte —> 28 ioMisc pointer —> 48 ioDirID long word Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume opWrErr File already open for writing permErr Attempt to open locked file for writing tmfoErr Too many files open æKY PBHCreate æFp Files.p æT FUNCTION æD FUNCTION PBHCreate(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHCreate(paramBlock,async); æRI IV-146 æC Trap macro _HCreate Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 48 ioDirID long word PBHCreate is identical to PBCreate except that it accepts a directory ID in ioDirID. Note: To create a directory instead of a file, call PBDirCreate. Result codes noErr No error bdNamErr Bad file name dupFNErr Duplicate file name and version dirFulErr File directory full dirNFErr Directory not found or incomplete pathname extFSErr External file system ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBHDelete æFp Files.p æT FUNCTION æD FUNCTION PBHDelete(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHDelete(paramBlock,async); æRI IV-147, VI æC Some existing HFS functions now support file IDs as appropriate, but their interface remains stable. This section describes how they accommodate file IDs. FUNCTION PBHDelete (paramBlock: HParamBlkPtr, async: Boolean) : OSErr; If a file ID exists for the file being deleted, the file ID is also deleted. Trap macro _HDelete Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 48 ioDirID long word PBHDelete is identical to PBDelete except that it accepts a directory ID in ioDirID. PBHDelete can be used to delete an empty directory as well. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fBsyErr File busy, directory not empty, or working directory control block open fLckdErr File locked fnfErr File not found nsvErr No such volume ioErr I/O error vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBHRename æFp Files.p æT FUNCTION æD FUNCTION PBHRename(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHRename(paramBlock,async); æRI IV-154, VI æC Some existing HFS functions now support file IDs as appropriate, but their interface remains stable. This section describes how they accommodate file IDs. FUNCTION PBHRename (paramBlock: HParamBlkPtr, async: Boolean) : OSErr; If a file ID exists for the file being renamed, the file ID remains with the file. _____________________________________________________________________________ Trap macro _HRename Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 28 ioMisc pointer --> 48 ioDirID long word PBHRename is identical to PBRename except that it accepts a directory ID in ioDirID and can be used to rename directories as well as files and volumes. Given a pointer to the name of a file or directory in ioNamePtr, PBHRename changes it to the name pointed to by ioMisc. Given a pointer to a volume name in ioNamePtr or a volume reference number in ioVRefNum, it changes the name of the volume to the name pointed to by ioMisc. Warning: PBHRename cannot be used to change the directory a file is in. Result codes noErr No error bdNamErr Bad file name dirFulErr File directory full dirNFErr Directory not found or incomplete pathname dupFNErr Duplicate file name and version extFSErr External file system fLckdErr File locked fnfErr File not found fsRnErr Problem during rename ioErr I/O error nsvErr No such volume paramErr No default volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBHRstFLock æFp Files.p æT FUNCTION æD FUNCTION PBHRstFLock(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHRstFLock(paramBlock,async); æRI IV-152 æC Trap macro _HRstFLock Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 48 ioDirID long word PBHRstFLock is identical to PBRstFLock except that it accepts a directory ID in ioDirID. Result codes noErr No error dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBHSetFLock æFp Files.p æT FUNCTION æD FUNCTION PBHSetFLock(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHSetFLock(paramBlock,async); æRI IV-151 æC Trap macro _HSetFLock Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 48 ioDirID long word PBHSetFLock is identical to PBSetFLock except that it accepts a directory ID in ioDirID. Result codes noErr No error dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBHGetFInfo æFp Files.p æT FUNCTION æD FUNCTION PBHGetFInfo(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHGetFInfo(paramBlock,async); æRI IV-149 æC Trap macro _HGetFileInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word <-> 18 ioNamePtr pointer --> 22 ioVRefNum word <-- 24 ioFRefNum word --> 28 ioFDirIndex word <-- 30 ioFlAttrib byte <-- 32 ioFlFndrInfo 16 bytes <-> 48 ioDirID long word <-- 52 ioFlStBlk word <-- 54 ioFlLgLen long word <-- 58 ioFlPyLen long word <-- 62 ioFlRStBlk word <-- 64 ioFlRLgLen long word <-- 68 ioFlRPyLen long word <-- 72 ioFlCrDat long word <-- 76 ioFlMdDat long word PBHGetFInfo is identical to PBGetFInfo except that it accepts a directory ID in ioDirID. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fnfErr File not found ioErr I/O error nsvErr No such volume paramErr No default volume æKY PBHSetFInfo æFp Files.p æT FUNCTION æD FUNCTION PBHSetFInfo(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBHSetFInfo(paramBlock,async); æRI IV-150 æC Trap macro _HSetFileInfo Parameter block --> 12 ioCompletion pointer <-- 16 ioResult word --> 18 ioNamePtr pointer --> 22 ioVRefNum word --> 32 ioFlFndrInfo 16 bytes --> 48 ioDirID long word --> 72 ioFlCrDat long word --> 76 ioFlMdDat long word PBHSetFInfo is identical to PBSetFInfo except that it accepts a directory ID in ioDirID. Result codes noErr No error bdNamErr Bad file name dirNFErr Directory not found or incomplete pathname extFSErr External file system fLckdErr File locked fnfErr File not found ioErr I/O error nsvErr No such volume vLckdErr Software volume lock wPrErr Hardware volume lock æKY PBGetAltAccess æFp Files.p æT FUNCTION æD FUNCTION PBGetAltAccess(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBGetAltAccess(paramBlock,async); æRI VI æC Parameter block Æ 12 ioCompletion long pointer to completion routine ¨ 16 ioResult word result code Æ 18 ioNamePtr long pointer to volume name ¨ 22 ioVRefNum word volume reference number ¨ 32 ioBuffer long pointer to privilege info buffer Æ 36 ioReqCount long size allocated for buffer ¨ 40 ioActCount long amount used in buffer ¨ 44 ioAccessInfo1 long information specific to privilege model ¨ 48 ioAccessInfo2 long information specific to privilege model ¨ 52 ioAccessInfo3 long information specific to privilege model ¨ 56 ioAccessInfo4 long information specific to privilege model Æ 60 ioDirID word parent directory ID PBGetAltAccess retrieves access information from a volume managed by a file system that uses a privilege model different from the AFP model. Result codes <to come> æKY PBSetAltAccess æFp Files.p æT FUNCTION æD FUNCTION PBSetAltAccess(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBSetAltAccess(paramBlock,async); æRI VI æC Parameter block Æ 12 ioCompletion long pointer to completion routine ¨ 16 ioResult word result code Æ 18 ioNamePtr long pointer to volume name Æ 22 ioVRefNum word volume reference number ¨ 32 ioBuffer long pointer to privilege info buffer Æ 36 ioReqCount long size allocated for buffer ¨ 40 ioActCount long amount used in buffer Æ 44 ioAccessInfo1 long information specific to privilege model Æ 48 ioAccessInfo2 long information specific to privilege model Æ 52 ioAccessInfo3 long information specific to privilege model Æ 56 ioAccessInfo4 long information specific to privilege model Æ 60 ioDirID word parent directory ID PBSetAltAccess modifies access information from a volume managed by a file system that uses a privilege model different from the AFP model. Result codes <to come> æKY PBMakeFSSpec æFp Files.p æT FUNCTION æD FUNCTION PBMakeFSSpec(paramBlock: HParamBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBMakeFSSpec(paramBlock,async); æC æKY FInitQueue æFp Files.p æT PROCEDURE æTN A016 æD PROCEDURE FInitQueue; INLINE $A016; æDT FInitQueue; æRI II-103, IV-128 æC Trap macro _InitQueue FInitQueue clears all queued File Manager calls except the current one. æKY GetFSQHdr æFp Files.p æT FUNCTION æD FUNCTION GetFSQHdr: QHdrPtr; æDT myVariable := GetFSQHdr; æRI II-125, IV-175 æC You can get a pointer to the header of the file I/O queue by calling the File Manager function GetFSQHdr. FUNCTION GetFSQHdr : QHdrPtr; [Not in ROM] GetFSQHdr returns a pointer to the header of the file I/O queue. Assembly-language note: The global variable FSQHdr contains the header of the file I/O queue. æKY GetDrvQHdr æFp Files.p æT FUNCTION æD FUNCTION GetDrvQHdr: QHdrPtr; æDT myVariable := GetDrvQHdr; æRI II-128, IV-181 æC You can get a pointer to the header of the drive queue by calling the File Manager function GetDrvQHdr. FUNCTION GetDrvQHdr : QHdrPtr; [Not in ROM] GetDrvQHdr returns a pointer to the header of the drive queue. Assembly-language note: The global variable DrvQHdr contains the header of the drive queue. The drive queue can support any number of drives, limited only by memory space. æKY GetVCBQHdr æFp Files.p æT FUNCTION æD FUNCTION GetVCBQHdr: QHdrPtr; æDT myVariable := GetVCBQHdr; æRI II-126, IV-178 æC You can get a pointer to the header of the volume-control-block queue by calling the File Manager function GetVCBQHdr. FUNCTION GetVCBQHdr : QHdrPtr; [Not in ROM] GetVCBQHdr returns a pointer to the header of the volume-control-block queue. Assembly-language note: The global variable VCBQHdr contains the header of the volume-control-block-queue. The default volume’s volume control block is pointed to by the global variable DefVCBPtr. æKY HGetVol æFp Files.p æT FUNCTION æD FUNCTION HGetVol(volName: StringPtr;VAR vRefNum: INTEGER;VAR dirID: LONGINT): OSErr; æDT myVariable := HGetVol(volName,vRefNum,dirID); æRI IV-132, VI æC HGetVol is an HFS version of the MFS function GetVol. It calls the function PBHGetVol, documented in the File Manager chapter of Volume IV. vRefNum can hold a volume reference number or a working directory reference number. dirID holds a directory ID. æKY HSetVol æFp Files.p æT FUNCTION æD FUNCTION HSetVol(volName: StringPtr;vRefNum: INTEGER;dirID: LONGINT): OSErr; æDT myVariable := HSetVol(volName,vRefNum,dirID); æRI IV-133, VI æC HSetVol is an HFS version of the MFS function GetVol. It calls the function PBHGetVol, documented in the File Manager chapter of Volume IV. vRefNum can hold a volume reference number or a working directory reference number. dirID holds a directory ID. <Note: Don’t use HSetVol or PBHSetVol.> æKY HOpen æFp Files.p æT FUNCTION æD FUNCTION HOpen(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255;permission: SignedByte; VAR refNum: INTEGER): OSErr; æDT myVariable := HOpen(vRefNum,dirID,fileName,permission,refNum); æRI IV-136, VI æC HOpen creates an access path to the data fork of a file. It is an HFS version of the MFS function Open. It calls the function PBHOpen, documented in the File Manager chapter of Volume IV. æKY HOpenRF æFp Files.p æT FUNCTION æD FUNCTION HOpenRF(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255;permission: SignedByte; VAR refNum: INTEGER): OSErr; æDT myVariable := HOpenRF(vRefNum,dirID,fileName,permission,refNum); æRI IV-137, VI æC HOpenRF creates an access path to the resource fork of a file. It is an HFS version of the MFS function OpenRF. It calls the function PBHOpenRF, documented in the File Manager chapter of Volume IV. æKY AllocContig æFp Files.p æT FUNCTION æD FUNCTION AllocContig(refNum: INTEGER;VAR count: LONGINT): OSErr; æDT myVariable := AllocContig(refNum,count); æRT 218 æRI IV-143 æC AllocContig is a high-level function that calls PBAllocContig. æKY HCreate æFp Files.p æT FUNCTION æD FUNCTION HCreate(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255;creator: OSType; fileType: OSType): OSErr; æDT myVariable := HCreate(vRefNum,dirID,fileName,creator,fileType); æRT 218 æRI IV-146, VI æC HCreate creates a new file and sets the type and creator. It is an HFS version of the MFS function Create. vRefNum can hold a volume reference number or a working directory reference number. dirID holds a directory ID. HCreate calls the function PBHCreate, documented in the File Manager chapter of Volume IV. æKY DirCreate æFp Files.p æT FUNCTION æD FUNCTION DirCreate(vRefNum: INTEGER;parentDirID: LONGINT;directoryName: Str255; VAR createdDirID: LONGINT): OSErr; æDT myVariable := DirCreate(vRefNum,parentDirID,directoryName,createdDirID); æRT 218 æRI IV-146 æC DirCreate is a high-level function that calls PBDirCreate. æKY HDelete æFp Files.p æT FUNCTION æD FUNCTION HDelete(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255): OSErr; æDT myVariable := HDelete(vRefNum,dirID,fileName); æRI IV-147 æC æKY HGetFInfo æFp Files.p æT FUNCTION æD FUNCTION HGetFInfo(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255;VAR fndrInfo: FInfo): OSErr; æDT myVariable := HGetFInfo(vRefNum,dirID,fileName,fndrInfo); æRI IV-149 æC æKY HSetFInfo æFp Files.p æT FUNCTION æD FUNCTION HSetFInfo(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255;fndrInfo: FInfo): OSErr; æDT myVariable := HSetFInfo(vRefNum,dirID,fileName,fndrInfo); æRI IV-150 æC æKY HSetFLock æFp Files.p æT FUNCTION æD FUNCTION HSetFLock(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255): OSErr; æDT myVariable := HSetFLock(vRefNum,dirID,fileName); æRI IV-151, VI æC HSetFLock locks a file: no new access paths to it can be created. It is an HFS version of the MFS function SetFLock. It calls the function PBHSetFLock, documented in the File Manager chapter of Volume IV. æKY HRstFLock æFp Files.p æT FUNCTION æD FUNCTION HRstFLock(vRefNum: INTEGER;dirID: LONGINT;fileName: Str255): OSErr; æDT myVariable := HRstFLock(vRefNum,dirID,fileName); æRI IV-152, VI æC HRstFLock unlocks a file. It is an HFS version of the MFS function RstFLock. It calls the function PBHRstFLock, documented in the File Manager chapter of Volume IV. æKY HRename æFp Files.p æT FUNCTION æD FUNCTION HRename(vRefNum: INTEGER;dirID: LONGINT;oldName: Str255;newName: Str255): OSErr; æDT myVariable := HRename(vRefNum,dirID,oldName,newName); æRI IV-154, VI æC HRename changes the name of a file or directory. It is an HFS version of the MFS function Rename. It calls the function PBHRename, documented in the File Manager chapter of Volume IV. æKY CatMove æFp Files.p æT FUNCTION æD FUNCTION CatMove(vRefNum: INTEGER;dirID: LONGINT;oldName: Str255;newDirID: LONGINT; newName: Str255): OSErr; æDT myVariable := CatMove(vRefNum,dirID,oldName,newDirID,newName); æRT 218 æRI IV-157 æC CatMove is a high-level function that calls PBCatMove. æKY OpenWD æFp Files.p æT FUNCTION æD FUNCTION OpenWD(vRefNum: INTEGER;dirID: LONGINT;procID: LONGINT;VAR wdRefNum: INTEGER): OSErr; æDT myVariable := OpenWD(vRefNum,dirID,procID,wdRefNum); æRT 218 æRI IV-158 æC OpenWD is a high-level function that calls PBOpenWD. æKY CloseWD æFp Files.p æT FUNCTION æD FUNCTION CloseWD(wdRefNum: INTEGER): OSErr; æDT myVariable := CloseWD(wdRefNum); æRT 218 æRI IV-158 æC CloseWD is a high-level function that calls PBCloseWD. æKY GetWDInfo æFp Files.p æT FUNCTION æD FUNCTION GetWDInfo(wdRefNum: INTEGER;VAR vRefNum: INTEGER;VAR dirID: LONGINT; VAR procID: LONGINT): OSErr; æDT myVariable := GetWDInfo(wdRefNum,vRefNum,dirID,procID); æRT 218 æRI IV-159 æC GetWDInfo is a high-level function that calls PBGetWDInfo. æKY PBExchangeFiles æFp Files.p æT FUNCTION æD FUNCTION PBExchangeFiles(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBExchangeFiles(paramBlock,async); æRI VI æC Parameter Block ¨ 16 ioResult word Æ 18 ioNamePtr string pointer Æ 22 ioVRefNum word Æ 28 ioDestNamePtr string pointer Æ 36 ioDestDirID long Æ 48 ioSrcDirID long You should use PBExchangeFiles if your application needs to preserve the file ID after moving the data into a new file. Typically, you use PBExchangeFiles after creating a new file during a safe save. You must specify both files, which must exist on the same volume. The file specified by [ioDestDirID, ioDestNamePtr] is exchanged with the file specified by [ioSrcDirID, ioNamePtr]. Both forks of the files are exchanged. Modification dates in the catalog record are exchanged, along with the fields accessed by HFS to locate the data of the files. All other catalog information remains unchanged. PBExchangeFiles works on either open or closed files. If either file is open, PBExchangeFiles updates any file control blocks associated with the file. PBExchangeFiles does not require that file IDs exist for the files being exchanged. Result codes: extFSErr -58 External file system ioErr -36 I/O error nsvErr -35 No such volume fnfErr -43 File not found fLckdErr -45 One or both files locked volOfflinErr -53 Volume is off-line wrgVolTypeErr -123 Not an HFS volume fidNotFoundErr -1300 File not found fidExists -1301 File ID already exists notAFileErr -1302 Specified file is a directory diffVolErr -xxxx Volume specifications in pathnames are not equivalent æKY PBCreateFileID æFp Files.p æT FUNCTION æD FUNCTION PBCreateFileID(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBCreateFileID(paramBlock,async); æRI VI æC Parameter Block ¨ 16 ioResult word Æ 18 ioNamePtr string pointer Æ 22 ioVRefNum word Æ 48 ioSrcDirID long ¨ 54 ioFileID long Given a volume reference number, file name, and parent directory ID, PBCreateFileID creates a record to hold the name and parent directory ID of the specified file. The actual value of the file ID is the same as the file number stored in the file record. If a file ID already exists for the file, the ID value is returned in ioFileID. Result codes extFSErr -58 External file system ioErr -36 I/O error nsvErr -35 No such volume volOfflinErr -53 Volume is offline vLckdErr -46 Software volume lock wPrErr -44 Hardware volume lock wrgVolTypeErr -123 Not an HFS volume fidNotFoundErr -1300 File not found fidExists -1301 File ID already exists notAFileErr -1302 Specified file is a directory æKY PBResolveFileID æFp Files.p æT FUNCTION æD FUNCTION PBResolveFileID(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBResolveFileID(paramBlock,async); æRI VI æC Parameter Block ¨ 16 ioResult word ´ 18 ioNamePtr string pointer Æ 22 ioVRefNum word ¨ 48 ioSrcDirID long Æ 54 ioFileID long PBResolveFileID returns the filename and parent directory ID of the file referred to by file ID in the ioFileID field. It places the filename in the string pointed to by ioNamePtr and the directory ID in ioSrcDirID. You must allocate memory <how much?> for the string before you make the call. If the name string is NIL, PBResolveFileID returns only the parent directory ID. If the name string is not NIL but is only a volume name, PBResolveFileID ignores the value in ioVRefNum, uses the volume name instead, and overwrites the name string with the filename. A return code of fidNotFound means that the specified file ID has become invalid either because the file was deleted or the file ID was destroyed by PBDeleteFileID. Result codes: extFSErr -58 External file system ioErr -36 I/O error nsvErr -35 No such volume volOfflinErr -53 Volume is off-line wrgVolTypeErr -123 Not an HFS volume fidNotFoundErr -1300 File ID not found fidExists -1301 File ID already exists notAFileErr -1302 Specified file is a directory æKY PBDeleteFileID æFp Files.p æT FUNCTION æD FUNCTION PBDeleteFileID(paramBlock: HParmBlkPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDeleteFileID(paramBlock,async); æRI VI æC Parameter Block ¨ 16 ioResult word Æ 18 ioNamePtr string pointer Æ 22 ioVRefNum word Æ 54 ioFileID long PBDeleteFileID invalidates a file ID on the volume specified by ioVRefNum or ioNamePtr. After it has invalidated a file ID, the File Manager can no longer resolve it to a filename and parent directory ID. The file ID is invalidated whether or not the target file referenced by that ID still exists. Result codes: extFSErr -58 External file system ioErr -36 I/O error nsvErr -35 No such volume volOfflinErr -53 Volume is offline vLckdErr -46 Software volume lock wPrErr -44 Hardware volume lock wrgVolTypeErr -123 Not an HFS volume fidNotFoundErr -1300 File ID not found fidExists -1301 File ID already exists notAFileErr -1302 Specified file is a directory æKY PBDTGetPath æFp Files.p æT FUNCTION æD FUNCTION PBDTGetPath(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTGetPath(paramBlock,async); æC æKY PBDTCloseDown æFp Files.p æT FUNCTION æD FUNCTION PBDTCloseDown(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTCloseDown(paramBlock,async); æC æKY PBDTAddIcon æFp Files.p æT FUNCTION æD FUNCTION PBDTAddIcon(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTAddIcon(paramBlock,async); æC æKY PBDTGetIcon æFp Files.p æT FUNCTION æD FUNCTION PBDTGetIcon(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTGetIcon(paramBlock,async); æC æKY PBDTGetIconInfo æFp Files.p æT FUNCTION æD FUNCTION PBDTGetIconInfo(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTGetIconInfo(paramBlock,async); æC æKY PBDTAddAPPL æFp Files.p æT FUNCTION æD FUNCTION PBDTAddAPPL(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTAddAPPL(paramBlock,async); æC æKY PBDTRemoveAPPL æFp Files.p æT FUNCTION æD FUNCTION PBDTRemoveAPPL(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTRemoveAPPL(paramBlock,async); æC æKY PBDTGetAPPL æFp Files.p æT FUNCTION æD FUNCTION PBDTGetAPPL(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTGetAPPL(paramBlock,async); æC æKY PBDTSetComment æFp Files.p æT FUNCTION æD FUNCTION PBDTSetComment(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTSetComment(paramBlock,async); æC æKY PBDTRemoveComment æFp Files.p æT FUNCTION æD FUNCTION PBDTRemoveComment(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTRemoveComment(paramBlock,async); æC æKY PBDTGetComment æFp Files.p æT FUNCTION æD FUNCTION PBDTGetComment(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTGetComment(paramBlock,async); æC æKY PBDTFlush æFp Files.p æT FUNCTION æD FUNCTION PBDTFlush(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTFlush(paramBlock,async); æC æKY PBDTReset æFp Files.p æT FUNCTION æD FUNCTION PBDTReset(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTReset(paramBlock,async); æC æKY PBDTGetInfo æFp Files.p æT FUNCTION æD FUNCTION PBDTGetInfo(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTGetInfo(paramBlock,async); æC æKY PBDTOpenInform æFp Files.p æT FUNCTION æD FUNCTION PBDTOpenInform(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTOpenInform(paramBlock,async); æC æKY PBDTDelete æFp Files.p æT FUNCTION æD FUNCTION PBDTDelete(paramBlock: DTPBPtr;async: BOOLEAN): OSErr; æDT myVariable := PBDTDelete(paramBlock,async); æC æKY MakeFSSpec æFp Files.p æT FUNCTION æD { FSSpec Glue } FUNCTION MakeFSSpec(vRefNum: INTEGER;dirID: LONGINT;fileName: StringPtr): OSErr; æDT myVariable := MakeFSSpec(vRefNum,dirID,fileName); æRI VI æC You use the MakeFSSpec function to establish the canonical form of the name for a file, folder, or volume. MakeFSSpec places the canonical form of the specified file reference in the CanonicalFileSpec parameter. (See “Identifying Files, Folders, and Volumes” for a description of the FSSpec record.) The vRefNum parameter is the volume reference number, a working directory reference number, a drive number, or 0 for the default volume. The dirID parameter is the parent directory ID of the target object. If the directory is sufficiently specified by either vRefNum or fileName, dirID can be 0. If you explicitly specify dirID (that is, if it is any value other than 0), and if vRefNum is a working directory reference number, dirID overrides the directory ID included in vRefNum. The fileName parameter is a full or partial pathname. If it is a full pathname, MakeFSSpec ignores vRefNum and dirID. A partial pathname might identify only the final target, or it might include one or more parent folder names. If fileName is a partial pathname, vRefNum, dirID, or both must be valid. You can pass the input to MakeFSSpec in any of the four ways described in “Identifying Files, Folders, and Volumes” earlier in this chapter. See “Using the File Manager” for a summary of the how MakeFSSpec accepts input and how it fills in the FSSpec record for files, folders, and volumes. In addition to the result code listed here, MakeFSSpec can return a number of different File Manager or Memory Manager error codes. Result codes paramErr -50 Output is NIL æKY FSpOpenDF æFp Files.p æT FUNCTION æD FUNCTION FSpOpenDF(spec: FSSpecPtr;permission: Byte;VAR refNum: INTEGER): OSErr; æDT myVariable := FSpOpenDF(spec,permission,refNum); æC æKY FSpOpenRF æFp Files.p æT FUNCTION æD FUNCTION FSpOpenRF(spec: FSSpecPtr;permission: Byte;VAR refNum: INTEGER): OSErr; æDT myVariable := FSpOpenRF(spec,permission,refNum); æC æKY FSpCreate æFp Files.p æT FUNCTION æD FUNCTION FSpCreate(spec: FSSpecPtr;creator: OSType;fileType: OSType): OSErr; æDT myVariable := FSpCreate(spec,creator,fileType); æC æKY FSpDirCreate æFp Files.p æT FUNCTION æD FUNCTION FSpDirCreate(spec: FSSpecPtr;VAR createdDirID: LONGINT): OSErr; æDT myVariable := FSpDirCreate(spec,createdDirID); æC æKY FSpDelete æFp Files.p æT FUNCTION æD FUNCTION FSpDelete(spec: FSSpecPtr): OSErr; æDT myVariable := FSpDelete(spec); æC æKY FSpGetFInfo æFp Files.p æT FUNCTION æD FUNCTION FSpGetFInfo(spec: FSSpecPtr;VAR fndrInfo: FInfo): OSErr; æDT myVariable := FSpGetFInfo(spec,fndrInfo); æC æKY FSpSetFInfo æFp Files.p æT FUNCTION æD FUNCTION FSpSetFInfo(spec: FSSpecPtr;VAR fndrInfo: FInfo): OSErr; æDT myVariable := FSpSetFInfo(spec,fndrInfo); æC æKY FSpSetFLock æFp Files.p æT FUNCTION æD FUNCTION FSpSetFLock(spec: FSSpecPtr): OSErr; æDT myVariable := FSpSetFLock(spec); æC æKY FSpRstFLock æFp Files.p æT FUNCTION æD FUNCTION FSpRstFLock(spec: FSSpecPtr): OSErr; æDT myVariable := FSpRstFLock(spec); æC æKY FSpRename æFp Files.p æT FUNCTION æD FUNCTION FSpRename(spec: FSSpecPtr;newName: StringPtr): OSErr; æDT myVariable := FSpRename(spec,newName); æC æKY FSpCatMove æFp Files.p æT FUNCTION æD FUNCTION FSpCatMove(source: FSSpecPtr;dest: FSSpecPtr): OSErr; æDT myVariable := FSpCatMove(source,dest); æC æKY FSpOpenResFile æFp Files.p æT FUNCTION æD FUNCTION FSpOpenResFile(spec: FSSpecPtr;permission: Byte): INTEGER; æDT myVariable := FSpOpenResFile(spec,permission); æC æKY FSpCreateResFile æFp Files.p æT PROCEDURE æD PROCEDURE FSpCreateResFile(spec: FSSpecPtr); æDT FSpCreateResFile(spec); æC æKY FixMath.p æKL Fix2Frac Fix2Long Fix2X FixATan2 FixDiv Frac2Fix Frac2X FracCos FracDiv FracMul FracSin FracSqrt Long2Fix X2Fix X2Frac æKY Fix2Frac æFp FixMath.p æT FUNCTION æTN A841 æD FUNCTION Fix2Frac(x: Fixed): Fract; INLINE $A841; { Long2Fix, Fix2Long, Fix2Frac, and Frac2Fix convert between fixed-point types. } æDT myVariable := Fix2Frac(x); æRI IV-65 æC Long2Fix, Fix2Long, Fix2Frac, and Frac2Fix convert between fixed-point types. Examples Examples of the use of these fixed-point functions are provided below; all numbers are decimal unless otherwise noted. Function Result Comment FixDiv (X2Fix(1.95), X2Fix(1.30)) $00018000 1.5 = 01.10 bin FracDiv (X2Frac(1.95), X2Frac(1.30)) $60000000 1.5 = 01.10 bin FracMul (X2Frac(1.50), X2Frac(1.30)) $7CCCCCCD 1.95 rounded FracSqrt (X2Frac(1.96)) $5999999A 1.4 rounded FracSin (X2Fix(3.1416015625)) $00000000 0 FracCos (X2Fix(3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(1.75)) $00000002 2 Fix2Frac (X2Fix(1.75)) $70000000 1.75 = 01.11 bin Frac2Fix (X2Frac(1.75)) $0001C000 1.75 = 01.11 bin FixATan2 (X2Fix(1.00), X2Fix(1.00)) $0000C910 0.C910 hex = X2Fix (π/4) FixDiv (X2Fix(-1.95), X2Fix(1.30)) $FFFE8000 -1.5 FracDiv (X2Frac(-1.95), X2Frac(1.30)) $A0000000 -1.5 FracMul (X2Frac(-1.50), X2Frac(1.30)) $83333333 -1.95 rounded FracSin (X2Fix(-3.1416015625)) $00000000 0 FracCos (X2Fix(-3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(-1.75)) $FFFFFFFE -2 Fix2Frac (X2Fix(-1.75)) $90000000 -1.75 Frac2Fix (X2Frac(-1.75)) $FFFE4000 -1.75 FixATan2 (X2Fix(-1.00), X2Fix(-1.00)) $FFFDA4D0 -3*X2Fix(π/4)=3*0.C910 hex æKY Fix2Long æFp FixMath.p æT FUNCTION æTN A840 æD FUNCTION Fix2Long(x: Fixed): LONGINT; INLINE $A840; æDT myVariable := Fix2Long(x); æRI IV-65 æC Long2Fix, Fix2Long, Fix2Frac, and Frac2Fix convert between fixed-point types. Examples Examples of the use of these fixed-point functions are provided below; all numbers are decimal unless otherwise noted. Function Result Comment FixDiv (X2Fix(1.95), X2Fix(1.30)) $00018000 1.5 = 01.10 bin FracDiv (X2Frac(1.95), X2Frac(1.30)) $60000000 1.5 = 01.10 bin FracMul (X2Frac(1.50), X2Frac(1.30)) $7CCCCCCD 1.95 rounded FracSqrt (X2Frac(1.96)) $5999999A 1.4 rounded FracSin (X2Fix(3.1416015625)) $00000000 0 FracCos (X2Fix(3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(1.75)) $00000002 2 Fix2Frac (X2Fix(1.75)) $70000000 1.75 = 01.11 bin Frac2Fix (X2Frac(1.75)) $0001C000 1.75 = 01.11 bin FixATan2 (X2Fix(1.00), X2Fix(1.00)) $0000C910 0.C910 hex = X2Fix (π/4) FixDiv (X2Fix(-1.95), X2Fix(1.30)) $FFFE8000 -1.5 FracDiv (X2Frac(-1.95), X2Frac(1.30)) $A0000000 -1.5 FracMul (X2Frac(-1.50), X2Frac(1.30)) $83333333 -1.95 rounded FracSin (X2Fix(-3.1416015625)) $00000000 0 FracCos (X2Fix(-3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(-1.75)) $FFFFFFFE -2 Fix2Frac (X2Fix(-1.75)) $90000000 -1.75 Frac2Fix (X2Frac(-1.75)) $FFFE4000 -1.75 FixATan2 (X2Fix(-1.00), X2Fix(-1.00)) $FFFDA4D0 -3*X2Fix(π/4)=3*0.C910 hex æKY FixATan2 æFp FixMath.p æT FUNCTION æTN A818 æD FUNCTION FixATan2(x: LONGINT;y: LONGINT): Fixed; INLINE $A818; æDT myVariable := FixATan2(x,y); æRI IV-65 æC FixATan2 returns the arctangent of y / x in radians. Note that FixATan2 effects “arctan(type / type) --> Fixed”: arctan(LONGINT / LONGINT) --> Fixed arctan(Fixed / Fixed) --> Fixed arctan(Fract / Fract) --> Fixed æKY Long2Fix æFp FixMath.p æT FUNCTION æTN A83F æD FUNCTION Long2Fix(x: LONGINT): Fixed; INLINE $A83F; æDT myVariable := Long2Fix(x); æRI IV-65 æC Long2Fix, Fix2Long, Fix2Frac, and Frac2Fix convert between fixed-point types. Examples Examples of the use of these fixed-point functions are provided below; all numbers are decimal unless otherwise noted. Function Result Comment FixDiv (X2Fix(1.95), X2Fix(1.30)) $00018000 1.5 = 01.10 bin FracDiv (X2Frac(1.95), X2Frac(1.30)) $60000000 1.5 = 01.10 bin FracMul (X2Frac(1.50), X2Frac(1.30)) $7CCCCCCD 1.95 rounded FracSqrt (X2Frac(1.96)) $5999999A 1.4 rounded FracSin (X2Fix(3.1416015625)) $00000000 0 FracCos (X2Fix(3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(1.75)) $00000002 2 Fix2Frac (X2Fix(1.75)) $70000000 1.75 = 01.11 bin Frac2Fix (X2Frac(1.75)) $0001C000 1.75 = 01.11 bin FixATan2 (X2Fix(1.00), X2Fix(1.00)) $0000C910 0.C910 hex = X2Fix (π/4) FixDiv (X2Fix(-1.95), X2Fix(1.30)) $FFFE8000 -1.5 FracDiv (X2Frac(-1.95), X2Frac(1.30)) $A0000000 -1.5 FracMul (X2Frac(-1.50), X2Frac(1.30)) $83333333 -1.95 rounded FracSin (X2Fix(-3.1416015625)) $00000000 0 FracCos (X2Fix(-3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(-1.75)) $FFFFFFFE -2 Fix2Frac (X2Fix(-1.75)) $90000000 -1.75 Frac2Fix (X2Frac(-1.75)) $FFFE4000 -1.75 FixATan2 (X2Fix(-1.00), X2Fix(-1.00)) $FFFDA4D0 -3*X2Fix(π/4)=3*0.C910 hex æKY Frac2Fix æFp FixMath.p æT FUNCTION æTN A842 æD FUNCTION Frac2Fix(x: Fract): Fixed; INLINE $A842; æDT myVariable := Frac2Fix(x); æRI IV-65 æC Long2Fix, Fix2Long, Fix2Frac, and Frac2Fix convert between fixed-point types. Examples Examples of the use of these fixed-point functions are provided below; all numbers are decimal unless otherwise noted. Function Result Comment FixDiv (X2Fix(1.95), X2Fix(1.30)) $00018000 1.5 = 01.10 bin FracDiv (X2Frac(1.95), X2Frac(1.30)) $60000000 1.5 = 01.10 bin FracMul (X2Frac(1.50), X2Frac(1.30)) $7CCCCCCD 1.95 rounded FracSqrt (X2Frac(1.96)) $5999999A 1.4 rounded FracSin (X2Fix(3.1416015625)) $00000000 0 FracCos (X2Fix(3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(1.75)) $00000002 2 Fix2Frac (X2Fix(1.75)) $70000000 1.75 = 01.11 bin Frac2Fix (X2Frac(1.75)) $0001C000 1.75 = 01.11 bin FixATan2 (X2Fix(1.00), X2Fix(1.00)) $0000C910 0.C910 hex = X2Fix (π/4) FixDiv (X2Fix(-1.95), X2Fix(1.30)) $FFFE8000 -1.5 FracDiv (X2Frac(-1.95), X2Frac(1.30)) $A0000000 -1.5 FracMul (X2Frac(-1.50), X2Frac(1.30)) $83333333 -1.95 rounded FracSin (X2Fix(-3.1416015625)) $00000000 0 FracCos (X2Fix(-3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(-1.75)) $FFFFFFFE -2 Fix2Frac (X2Fix(-1.75)) $90000000 -1.75 Frac2Fix (X2Frac(-1.75)) $FFFE4000 -1.75 FixATan2 (X2Fix(-1.00), X2Fix(-1.00)) $FFFDA4D0 -3*X2Fix(π/4)=3*0.C910 hex æKY Frac2X æFp FixMath.p æT FUNCTION æD FUNCTION Frac2X(x: Fract): extended; æDT myVariable := Frac2X(x); æRI IV-65 æC Fix2X, X2Fix, Frac2X, and X2Frac convert between Fixed and Fract and the Extended floating-point type. These functions do not set floating-point exception flags. Examples Examples of the use of these fixed-point functions are provided below; all numbers are decimal unless otherwise noted. Function Result Comment FixDiv (X2Fix(1.95), X2Fix(1.30)) $00018000 1.5 = 01.10 bin FracDiv (X2Frac(1.95), X2Frac(1.30)) $60000000 1.5 = 01.10 bin FracMul (X2Frac(1.50), X2Frac(1.30)) $7CCCCCCD 1.95 rounded FracSqrt (X2Frac(1.96)) $5999999A 1.4 rounded FracSin (X2Fix(3.1416015625)) $00000000 0 FracCos (X2Fix(3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(1.75)) $00000002 2 Fix2Frac (X2Fix(1.75)) $70000000 1.75 = 01.11 bin Frac2Fix (X2Frac(1.75)) $0001C000 1.75 = 01.11 bin FixATan2 (X2Fix(1.00), X2Fix(1.00)) $0000C910 0.C910 hex = X2Fix (π/4) FixDiv (X2Fix(-1.95), X2Fix(1.30)) $FFFE8000 -1.5 FracDiv (X2Frac(-1.95), X2Frac(1.30)) $A0000000 -1.5 FracMul (X2Frac(-1.50), X2Frac(1.30)) $83333333 -1.95 rounded FracSin (X2Fix(-3.1416015625)) $00000000 0 FracCos (X2Fix(-3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(-1.75)) $FFFFFFFE -2 Fix2Frac (X2Fix(-1.75)) $90000000 -1.75 Frac2Fix (X2Frac(-1.75)) $FFFE4000 -1.75 FixATan2 (X2Fix(-1.00), X2Fix(-1.00)) $FFFDA4D0 -3*X2Fix(π/4)=3*0.C910 hex æKY Fix2X æFp FixMath.p æT FUNCTION æD FUNCTION Fix2X(x: Fixed): extended; æDT myVariable := Fix2X(x); æRI IV-65 æC Fix2X, X2Fix, Frac2X, and X2Frac convert between Fixed and Fract and the Extended floating-point type. These functions do not set floating-point exception flags. Examples Examples of the use of these fixed-point functions are provided below; all numbers are decimal unless otherwise noted. Function Result Comment FixDiv (X2Fix(1.95), X2Fix(1.30)) $00018000 1.5 = 01.10 bin FracDiv (X2Frac(1.95), X2Frac(1.30)) $60000000 1.5 = 01.10 bin FracMul (X2Frac(1.50), X2Frac(1.30)) $7CCCCCCD 1.95 rounded FracSqrt (X2Frac(1.96)) $5999999A 1.4 rounded FracSin (X2Fix(3.1416015625)) $00000000 0 FracCos (X2Fix(3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(1.75)) $00000002 2 Fix2Frac (X2Fix(1.75)) $70000000 1.75 = 01.11 bin Frac2Fix (X2Frac(1.75)) $0001C000 1.75 = 01.11 bin FixATan2 (X2Fix(1.00), X2Fix(1.00)) $0000C910 0.C910 hex = X2Fix (π/4) FixDiv (X2Fix(-1.95), X2Fix(1.30)) $FFFE8000 -1.5 FracDiv (X2Frac(-1.95), X2Frac(1.30)) $A0000000 -1.5 FracMul (X2Frac(-1.50), X2Frac(1.30)) $83333333 -1.95 rounded FracSin (X2Fix(-3.1416015625)) $00000000 0 FracCos (X2Fix(-3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(-1.75)) $FFFFFFFE -2 Fix2Frac (X2Fix(-1.75)) $90000000 -1.75 Frac2Fix (X2Frac(-1.75)) $FFFE4000 -1.75 FixATan2 (X2Fix(-1.00), X2Fix(-1.00)) $FFFDA4D0 -3*X2Fix(π/4)=3*0.C910 hex æKY X2Fix æFp FixMath.p æT FUNCTION æD FUNCTION X2Fix(x: extended): Fixed; æDT myVariable := X2Fix(x); æRI IV-65 æC Fix2X, X2Fix, Frac2X, and X2Frac convert between Fixed and Fract and the Extended floating-point type. These functions do not set floating-point exception flags. Examples Examples of the use of these fixed-point functions are provided below; all numbers are decimal unless otherwise noted. Function Result Comment FixDiv (X2Fix(1.95), X2Fix(1.30)) $00018000 1.5 = 01.10 bin FracDiv (X2Frac(1.95), X2Frac(1.30)) $60000000 1.5 = 01.10 bin FracMul (X2Frac(1.50), X2Frac(1.30)) $7CCCCCCD 1.95 rounded FracSqrt (X2Frac(1.96)) $5999999A 1.4 rounded FracSin (X2Fix(3.1416015625)) $00000000 0 FracCos (X2Fix(3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(1.75)) $00000002 2 Fix2Frac (X2Fix(1.75)) $70000000 1.75 = 01.11 bin Frac2Fix (X2Frac(1.75)) $0001C000 1.75 = 01.11 bin FixATan2 (X2Fix(1.00), X2Fix(1.00)) $0000C910 0.C910 hex = X2Fix (π/4) FixDiv (X2Fix(-1.95), X2Fix(1.30)) $FFFE8000 -1.5 FracDiv (X2Frac(-1.95), X2Frac(1.30)) $A0000000 -1.5 FracMul (X2Frac(-1.50), X2Frac(1.30)) $83333333 -1.95 rounded FracSin (X2Fix(-3.1416015625)) $00000000 0 FracCos (X2Fix(-3.1416015625)) $C0000000 -1 Fix2Long (X2Fix(-1.75)) $FFFFFFFE -2 Fix2Frac (X2Fix(-1.75)) $90000000 -1.75 Frac2Fix (X2Frac(-1.75)) $FFFE4000 -1.75 FixATan2 (X2Fix(-1.00), X2Fix(-1.00)) $FFFDA4D0 -3*X2Fix(π/4)=3*0.C910 hex æKY X2Frac æFp FixMath.p æT FUNCTION æD FUNCTION X2Frac(x: extended): Fract; æDT myVariable := X2Frac(x); æRI X2Frac function IV-65 æC FUNCTION X2Frac (x: Extended) : Fract; Fix2X, X2Fix, Frac2X, and X2Frac convert between Fixed and Fract and the Extended floating-point type. These functions do not set floating-point exception flags. æKY FracMul æFp FixMath.p æT FUNCTION æTN A84A æD FUNCTION FracMul(x: Fract;y: Fract): Fract; INLINE $A84A; æDT myVariable := FracMul(x,y); æRI IV-64 æC FracMul returns x * y. Note that FracMul effects “type * Fract --> type”: Fract * Fract --> Fract LONGINT * Fract --> LONGINT Fract * LONGINT --> LONGINT Fixed * Fract --> Fixed Fract * Fixed --> Fixed æKY FixDiv æFp FixMath.p æT FUNCTION æTN A84D æD FUNCTION FixDiv(x: Fixed;y: Fixed): Fixed; INLINE $A84D; æDT myVariable := FixDiv(x,y); æRI IV-64 æC FixDiv returns x / y. Note that FixDiv effects “type / type --> Fixed” and “type / Fixed --> type”: Fixed / Fixed --> Fixed LONGINT / LONGINT --> Fixed Fract / Fract --> Fixed LONGINT / Fixed --> LONGINT Fract / Fixed --> Fract æKY FracDiv æFp FixMath.p æT FUNCTION æTN A84B æD FUNCTION FracDiv(x: Fract;y: Fract): Fract; INLINE $A84B; æDT myVariable := FracDiv(x,y); æRI IV-64 æC FracDiv returns x / y. Note that FracDiv effects “type / type --> Fract” and “type / Fract --> type”: Fract / Fract --> Fract LONGINT / LONGINT --> Fract Fixed / Fixed --> Fract LONGINT / Fract --> LONGINT Fixed / Fract --> Fixed æKY FracSqrt æFp FixMath.p æT FUNCTION æTN A849 æD FUNCTION FracSqrt(x: Fract): Fract; INLINE $A849; æDT myVariable := FracSqrt(x); æRI IV-64 æC FracSqrt returns the square root of x, with x interpreted as unsigned in the range 0 through 4–(2–30), inclusive: That is, bit 15 in Figure 1 has weight 2 rather than –2. The result, too, is unsigned in the range 0 through 2, inclusive. æKY FracSin æFp FixMath.p æT FUNCTION æTN A848 æD FUNCTION FracSin(x: Fixed): Fract; INLINE $A848; æDT myVariable := FracSin(x); æRI IV-64 æC FracCos and FracSin return the cosine and sine of their radian arguments, respectively. The hexadecimal value 0.C910 (which is FixATan2(1,1)) is the approximation to π/4 used for argument reduction. Thus, FracCos and FracSin are nearly periodic, but with period 2*P instead of 2*π, where P=3.1416015625 and π, of course, is 3.14159265.... æKY FracCos æFp FixMath.p æT FUNCTION æTN A847 æD FUNCTION FracCos(x: Fixed): Fract; INLINE $A847; æDT myVariable := FracCos(x); æRI IV-64 æC FracCos and FracSin return the cosine and sine of their radian arguments, respectively. The hexadecimal value 0.C910 (which is FixATan2(1,1)) is the approximation to π/4 used for argument reduction. Thus, FracCos and FracSin are nearly periodic, but with period 2*P instead of 2*π, where P=3.1416015625 and π, of course, is 3.14159265.... æKY Folders.p æKL FindFolder kAppleMenuFolderType kControlPanelFolderType kCreateFolder kDesktopFolderType kDontCreateFolder kExtensionFolderType kOnSystemDisk kPreferencesFolderType kSpoolFolderType kStartupFolderType kSystemFolderType kTemporaryFolderType kTrashFolderType kWhereToEmptyTrashFolderType æKY kOnSystemDisk æFp Folders.p æT CONST æD kOnSystemDisk = $8000; æC æKY kCreateFolder æFp Folders.p æT CONST æD kCreateFolder = TRUE; æC æKY kDontCreateFolder æFp Folders.p æT CONST æD kDontCreateFolder = FALSE; æC æKY kSystemFolderType æFp Folders.p æT CONST æD kSystemFolderType = 'macs'; {the system folder} æC æKY kDesktopFolderType æFp Folders.p æT CONST æD kDesktopFolderType = 'desk'; {the desktop folder; objects in this folder show on the desk top.} æC æKY kTrashFolderType æFp Folders.p æT CONST æD kTrashFolderType = 'trsh'; {the trash folder; objects in this folder show up in the trash} æC æKY kWhereToEmptyTrashFolderType æFp Folders.p æT CONST æD kWhereToEmptyTrashFolderType = 'empt'; {the "empty trash" folder; Finder starts empty from here down} æC æKY kSpoolFolderType æFp Folders.p æT CONST æD kSpoolFolderType = 'spoo'; {spool files go here (from the print drivers to the despooler} æC æKY kStartupFolderType æFp Folders.p æT CONST æD kStartupFolderType = 'strt'; {Finder objects (applications, documents, DAs, aliases, to...) to open at startup go here} æC æKY kAppleMenuFolderType æFp Folders.p æT CONST æD kAppleMenuFolderType = 'amnu'; {Finder objects to put into the Apple menu go here} æC æKY kControlPanelFolderType æFp Folders.p æT CONST æD kControlPanelFolderType = 'ctrl'; {Control Panels go here (may contain INITs)} æC æKY kExtensionFolderType æFp Folders.p æT CONST æD kExtensionFolderType = 'extn'; {Finder extensions go here} æC æKY kPreferencesFolderType æFp Folders.p æT CONST æD kPreferencesFolderType = 'pref'; {preferences for applications go here} æC æKY kTemporaryFolderType æFp Folders.p æT CONST æD kTemporaryFolderType = 'temp'; {temporary files go here (deleted periodically, but don't rely on it.)} æC æKY FindFolder æFp Folders.p æT FUNCTION æD FUNCTION FindFolder(vRefNum: INTEGER;folderType: OSType;createFolder: Boolean ; VAR foundVRefNum: INTEGER;VAR foundDirID: LONGINT): OSErr; INLINE $7000,$A823; æDT myVariable := FindFolder(vRefNum,folderType,createFolder,foundVRefNum,foundDirID); æC You can call the FindFolder function to get the path information so that you can access special folders. You pass FindFolder a target volume and a constant that tells it which special folder you are interested in. FindFolder returns a volume reference number and a directory ID. If the specified folder does not exist, FindFolder can create it and return the new directory ID. The Finder identifies the folder types and their names in a resource of type 'fld#'. Table 8-2 lists the folder types in version 7.0, their resource types, and the constants that represent them. Table 8-2. Special folders Folder Type Constant System Folder 'macs' kSystemFolderType Extensions folder 'extn' kExtensionFolderType Preferences folder 'pref' kPreferencesFolderType Apple Menu Folder 'amnu' kAppleMenuFolderType Startup Folder 'strt' kStartupFolderType Print Monitor Folder 'spoo' kSpoolFolderType Temporary folder 'temp' kTemporaryFolderType Desktop folder 'desk' kDesktopFolderType Single-user trash folder 'trsh' kTrashFolderType Shared trash folder 'empt' kSharedTrashFolderType In calls to FindFolder, you can use these three constants: CONST kOnSystemDisk = $8000; kCreateFolder = TRUE; kDontCreateFolder = FALSE; Call the FindFolder function to get a volume and directory ID for a special folder. FUNCTION FindFolder (vRefNum: Integer; folderType: OSType; createFolder: Boolean; VAR foundVRefNum: Integer; VAR foundDirID: LongInt) : OSErr; The FindFolder function returns the volume reference number and directory ID of a specified special folder on a specified volume. You specify a volume reference number (or the constant kOnSystemDisk for the boot disk) in the vRefNum parameter. You specify the folder type in the folderType parameter, using one of the constants listed in Table 8-2. The createFolder parameter tells FindFolder whether or not to create a folder if it does not already exist. FindFolder puts the results in foundVRefNum and foundDirID. Result codes fnfErr -43 Type not found in 'fld# resource; Folder not found and createFolder flag false dupFNErr -48 File found instead of folder æKY Fonts.p æKL FMSwapFont FontMetrics GetFNum GetFontName InitFonts RealFont SetFontLock SetFractEnable SetFScaleDisable appleMark applFont AsscEntry athens cairo checkMark commandMark courier diamondMark FamRec fixedFont FMetricRec FMInput FMOutPtr FMOutput FontAssoc FontRec fontWid fxdFntH fxdFntHW fxdFntW geneva helvetica KernEntry KernPair KernTable london losAngeles mobile monaco NameTable newYork propFont prpFntH prpFntHW prpFntW sanFran StyleTable symbol systemFont times toronto venice WidEntry WidTable WidthTable æKY systemFont æFp Fonts.p æT CONST æD systemFont = 0; æC _______________________________________________________________________________ »FONT NUMBERS _______________________________________________________________________________ Note: The information on Font Numbers described in the following paragraphs was originally documented in Inside Macintosh, Volume I. The Font Manager includes the following font numbers for identifying system-defined fonts: CONST systemFont = 0; {system font} applFont = 1; {application font} newYork = 2; geneva = 3; monaco = 4; venice = 5; london = 6; athens = 7; sanFran = 8; toronto = 9; cairo = 11; losAngeles = 12; times = 20; helvetica = 21; courier = 22; symbol = 23; taliesin = 24; The system font is so called because it’s the font used by the system (for drawing menu titles and commands in menus, for example). The name of the system font is Chicago. The size of text drawn by the system in this font is fixed at 12 points (called the system font size). The application font is the font your application will use unless you specify otherwise. Unlike the system font, the application font isn’t a separate font, but is essentially a reference to another font—Geneva, by default. (The application font number is determined by a value that you can set in parameter RAM; see the Operating System Utilities chapter for more information.) Assembly-language note: You can get the application font number from the global variable ApFontID. æKY applFont æFp Fonts.p æT CONST æD applFont = 1; æC æKY newYork æFp Fonts.p æT CONST æD newYork = 2; æC æKY geneva æFp Fonts.p æT CONST æD geneva = 3; æC æKY monaco æFp Fonts.p æT CONST æD monaco = 4; æC æKY venice æFp Fonts.p æT CONST æD venice = 5; æC æKY london æFp Fonts.p æT CONST æD london = 6; æC æKY athens æFp Fonts.p æT CONST æD athens = 7; æC æKY sanFran æFp Fonts.p æT CONST æD sanFran = 8; æC æKY toronto æFp Fonts.p æT CONST æD toronto = 9; æC æKY cairo æFp Fonts.p æT CONST æD cairo = 11; æC æKY losAngeles æFp Fonts.p æT CONST æD losAngeles = 12; æC æKY times æFp Fonts.p æT CONST æD times = 20; æC æKY helvetica æFp Fonts.p æT CONST æD helvetica = 21; æC æKY courier æFp Fonts.p æT CONST æD courier = 22; æC æKY symbol æFp Fonts.p æT CONST æD symbol = 23; æC æKY mobile æFp Fonts.p æT CONST æD mobile = 24; æC æKY commandMark æFp Fonts.p æT CONST æD commandMark = 17; æC _______________________________________________________________________________ »CHARACTERS IN A FONT _______________________________________________________________________________ Note: The information on the Characters In A Font described in the following paragraphs was originally documented in Inside Macintosh, Volume I. A font can consist of up to 255 distinct characters; not all characters need to be defined in a single font. Figure 20 shows the standard printing characters on the Macintosh and their ASCII codes (for example, the ASCII code for “A” is 41 hexadecimal, or 65 decimal). Note: Codes $00 through $1F and code $7F are normally nonprinting characters (see the Toolbox Event Manager chapter for details). The special characters in the system font with codes $11 through $14 can’t normally be typed from the keyboard or keypad. The Font Manager defines constants for these characters: CONST commandMark = $11; {Command key symbol} checkMark = $12; {check mark} diamondMark = $13; {diamond symbol} appleMark = $14; {apple symbol} In addition to its maximum of 255 characters, every font contains a missing symbol that’s drawn in case of a request to draw a character that’s missing from the font. •••Refer to Figure 20.••• Figure 20–Font Characters æKY checkMark æFp Fonts.p æT CONST æD checkMark = 18; æC æKY diamondMark æFp Fonts.p æT CONST æD diamondMark = 19; æC æKY appleMark æFp Fonts.p æT CONST æD appleMark = 20; æC æKY propFont æFp Fonts.p æT CONST æD propFont = 36864; æC æKY prpFntH æFp Fonts.p æT CONST æD prpFntH = 36865; æC æKY prpFntW æFp Fonts.p æT CONST æD prpFntW = 36866; æC æKY prpFntHW æFp Fonts.p æT CONST æD prpFntHW = 36867; æC æKY fixedFont æFp Fonts.p æT CONST æD fixedFont = 45056; æC æKY fxdFntH æFp Fonts.p æT CONST æD fxdFntH = 45057; æC æKY fxdFntW æFp Fonts.p æT CONST æD fxdFntW = 45058; æC æKY fxdFntHW æFp Fonts.p æT CONST æD fxdFntHW = 45059; æC æKY fontWid æFp Fonts.p æT CONST æD fontWid = 44208; æC æKY FMInput æFp Fonts.p æT RECORD æD FMInput = PACKED RECORD family: INTEGER; size: INTEGER; face: Style; needBits: BOOLEAN; device: INTEGER; numer: Point; denom: Point; END; æC _______________________________________________________________________________ »COMMUNICATION BETWEEN QUICKDRAW AND THE FONT MANAGER _______________________________________________________________________________ This section describes the data structures that allow QuickDraw and the Font Manager to exchange information. It also discusses the communication that may occur between the Font Manager and the driver of the device on which the characters are being drawn or printed. You can skip this section if you want to change fonts, character style, and font sizes by calling QuickDraw and aren’t interested in the lower-level data structures and routines of the Font Manager. To understand this section fully, you’ll have to be familiar with device drivers and the Device Manager. Whenever you call a QuickDraw routine that does anything with text, QuickDraw requests information from the Font Manager about the characters. The Font Manager performs any necessary calculations and returns the requested information to QuickDraw. As illustrated in Figure 21, this information exchange occurs via two data structures, a font input record (type FMInput) and a font output record (type FMOutput). First, QuickDraw passes the Font Manager a font input record: TYPE FMInput = PACKED RECORD family: INTEGER; {font number} size: INTEGER; {font size} face: Style; {character style} needBits: BOOLEAN; {TRUE if drawing} device: INTEGER; {device-specific information} numer: Point; {numerators of scaling factors} denom: Point {denominators of scaling factors} END; The first three fields contain the font number, size, and character style that QuickDraw wants to use. The needBits field indicates whether the characters actually will be drawn or not. If the characters are being drawn, all of the information describing the font, including the bit image comprising the characters, will be read into memory. If the characters aren’t being drawn and there’s a resource consisting of only the character widths and general font information, that resource will be read instead. The high-order byte of the device field contains a device driver reference number. From the driver reference number, the Font Manager can determine the optimum stylistic variations on the font to produce the highest-quality printing or drawing available on a device (as explained below). The low-order byte of the device field is ignored by the Font Manager but may contain information used by the device driver. •••Refer to Figure 21.••• Figure 21–Communication About Fonts The numer and denom fields contain the scaling factors to be used; numer.v divided by denom.v gives the vertical scaling, and numer.h divided by denom.h gives the horizontal scaling. The Font Manager takes the font input record and asks the Resource Manager for the font. If the requested size isn’t available, the Font Manager scales another size to match (as described under “Font Scaling”). Then the Font Manager gets the font characterization table via the device field. If the high-order byte of the device field is 0, the Font Manager gets the screen’s font characterization table (which is stored in the Font Manager). If the high-order byte of the device field is nonzero, the Font Manager calls the status routine of the device driver having that reference number, and the status routine returns a font characterization table. The status routine may use the value of the low-order byte of the device field to determine the font characterization table it should return. Note: If you want to make your own calls to the device driver’s Status function, the reference number must be the driver reference number from the font input record’s device field, csCode must be 8, csParam must be a pointer to where the device driver should put the font characterization table, and csParam+4 must be an integer containing the value of the font input record’s device field. Figure 22 shows the structure of a font characterization table and, on the right, the values it contains for the Macintosh screen. •••Refer to Figure 22.••• Figure 22–Font Characterization Table The first two words of the font characterization table contain the approximate number of dots per inch on the device. These values are only used for scaling between devices; they don’t necessarily correspond to a device’s actual resolution. The remainder of the table consists of three-byte triplets providing information about the different stylistic variations. For all but the triplet defining the underline characteristics: • The first byte in the triplet indicates which byte beyond the bold field of the font output record (see below) is affected by the triplet. • The second byte contains the amount to be stored in the affected field. • The third byte indicates the amount by which the extra field of the font output record is to be incremented (starting from 0). The triplet defining the underline characteristics indicates the amount by which the font output record’s ulOffset, ulShadow, and ulThick fields (respectively) should be incremented. æKY FMOutput FMOutPtr æFp Fonts.p æT RECORD æD FMOutPtr = ^FMOutput; FMOutput = PACKED RECORD errNum: INTEGER; fontHandle: Handle; bold: Byte; italic: Byte; ulOffset: Byte; ulShadow: Byte; ulThick: Byte; shadow: Byte; extra: SignedByte; ascent: Byte; descent: Byte; widMax: Byte; leading: SignedByte; unused: Byte; numer: Point; denom: Point; END; æC Based on the information in the font characterization table, the Font Manager determines the optimum ascent, descent, and leading, so that the highest-quality printing or drawing available will be produced. It then stores this information in a font output record: TYPE FMOutput = PACKED RECORD errNum: INTEGER; {not used} fontHandle: Handle; {handle to font record} bold: Byte; {bold factor} italic: Byte; {italic factor} ulOffset: Byte; {underline offset} ulShadow: Byte; {underline shadow} ulThick: Byte; {underline thickness} shadow: Byte; {shadow factor} extra: SignedByte; {width of style} ascent: Byte; {ascent} descent: Byte; {descent} widMax: Byte; {maximum character width} leading: SignedByte; {leading} unused: Byte; {not used} numer: Point; {numerators of scaling factors} denom: Point {denominators of scaling factors} END; ErrNum is reserved for future use, and is set to 0. FontHandle is a handle to the font record of the font, as described in the next section. Bold, italic, ulOffset, ulShadow, ulThick, and shadow are all fields that modify the way stylistic variations are done; their values are taken from the font characterization table, and are used by QuickDraw. (You’ll need to experiment with these values if you want to determine exactly how they’re used.) Extra indicates the number of pixels that each character has been widened by stylistic variation. For example, using the screen values shown in Figure 22, the extra field for bold shadowed characters would be 3. Ascent, descent, widMax, and leading are the same as the fields of the FontInfo record returned by the QuickDraw procedure GetFontInfo. Numer and denom contain the scaling factors. Just before returning this record to QuickDraw, the Font Manager calls the device driver’s control routine to allow the driver to make any final modifications to the record. Finally, the font information is returned to QuickDraw via a pointer to the record, defined as follows: TYPE FMOutPtr = ^FMOutput; Note: If you want to make your own calls to the device driver’s Control function, the reference number must be the driver reference number from the font input record’s device field, csCode must be 8, csParam must be a pointer to the font output record, and csParam+4 must be the value of the font input record’s device field. æKY FontRec æFp Fonts.p æT RECORD æD FontRec = RECORD fontType: INTEGER; {font type} firstChar: INTEGER; {ASCII code of first character} lastChar: INTEGER; {ASCII code of last character} widMax: INTEGER; {maximum character width} kernMax: INTEGER; {negative of maximum character kern} nDescent: INTEGER; {negative of descent} fRectWidth: INTEGER; {width of font rectangle} fRectHeight: INTEGER; {height of font rectangle} owTLoc: INTEGER; {offset to offset/width table} ascent: INTEGER; {ascent} descent: INTEGER; {descent} leading: INTEGER; {leading} rowWords: INTEGER; {row width of bit image / 2 } END; æC »Font Records The information describing a font is contained in a data structure called a font record, which contains the following: • the font type (fixed-width or proportional) • the ASCII code of the first character and the last character in the font • the maximum character width and maximum amount any character kerns • the font height, ascent, descent, and leading • the bit image of the font • a location table, which is an array of words specifying the location of each character image within the bit image • an offset/width table, which is an array of words specifying the character offset and character width for each character in the font For every character, the location table contains a word that specifies the bit offset to the location of that character’s image in the bit image. The entry for a character missing from the font contains the same value as the entry for the next character. The last word of the table contains the offset to one bit beyond the end of the bit image (that is, beyond the character image for the missing symbol). The image width of each character is determined from the location table by subtracting the bit offset to that character from the bit offset to the next character in the table. There’s also one word in the offset/width table for every character: The high-order byte specifies the character offset and the low order byte specifies the character width. Missing characters are flagged in this table by a word value of –1. The last word is also –1, indicating the end of the table. Note: The 64K ROM version of the Resource Manager limits the total space occupied by the bit image, location table, offset/width table, and character-width and image-height tables to 32K bytes. For this reason, the practical limit on the font size of a full font is about 40 points. Figure 9 illustrates a sample location table and offset/width table corresponding to the bit image in Figure 8 above. A font record is referred to by a handle that you can get by calling the FMSwapFont function or the Resource Manager function GetResource. The data type for a font record is as follows: TYPE FontRec = RECORD fontType: INTEGER; {font type} firstChar: INTEGER; {ASCII code of first character} lastChar: INTEGER; {ASCII code of last character} widMax: INTEGER; {maximum character width} kernMax: INTEGER; {negative of maximum character kern} nDescent: INTEGER; {negative of descent} fRectWidth: INTEGER; {width of font rectangle} fRectHeight: INTEGER; {height of font rectangle} owTLoc: INTEGER; {offset to offset/width table} ascent: INTEGER; {ascent} descent: INTEGER; {descent} leading: INTEGER; {leading} rowWords: INTEGER; {row width of bit image / 2} { bitImage: ARRAY[1..rowWords,1..fRectHeight] OF INTEGER; } {bit image} { locTable: ARRAY[firstChar..lastChar+2] OF INTEGER; } {location table} { owTable: ARRAY[firstChar..lastChar+2] OF INTEGER; } {offset/width table} END; Note: The variable-length arrays appear as comments because they’re not valid Pascal syntax; they’re used only as conceptual aids. •••Refer to Figure 9.••• Figure 9–Sample Location Table and Offset/Width Table The fontType field must contain one of the following predefined constants: CONST propFont = $9000; {proportional font} fixedFont = $B000; {fixed-width font} The values in the widMax, kernMax, nDescent, fRectWidth, fRectHeight, ascent, descent, and leading fields all specify a number of pixels. KernMax indicates the largest number of pixels any character kerns, that is, the distance from the character origin to the left edge of the font rectangle. It should always be 0 or negative, since the kerned pixels are to the left of the character origin. NDescent is the negative of the descent (the distance from the character origin to the bottom of the font rectangle). The owTLoc field contains a word offset from itself to the offset/width table; it’s equivalent to 4 + (rowWords * fRectHeight) + (lastChar–firstChar+3) + 1 Warning: Remember, the offset and row width in a font record are given in words, not bytes. Assembly-language note: The global variable ROMFont0 contains a handle to the font record for the system font. Every size of a font is stored as a separate resource. The resource type for a font is 'FONT'. The resource data for a font is simply a font record: Number of bytes Contents 2 bytes FontType field of font record 2 bytes FirstChar field of font record 2 bytes LastChar field of font record 2 bytes WidMax field of font record 2 bytes KernMax field of font record 2 bytes NDescent field of font record 2 bytes FRectWidth field of font record 2 bytes FRectHeight field of font record 2 bytes OWTLoc field of font record 2 bytes Ascent field of font record 2 bytes Descent field of font record 2 bytes Leading field of font record 2 bytes RowWords field of font record n bytes Bit image of font n = 2 * rowWords * fRectHeight m bytes Location table of font m = 2 * (lastChar–firstChar+3) m bytes Offset/width table of font m = 2 * (lastChar–firstChar+3) As shown in Figure 10, the resource ID of a font has the following format: Bits 0-6 are the font size, bits 7-14 are the font number, and bit 15 is 0. Thus the resource ID corresponding to a given font number and size is (128 * font number) + font size •••Refer to Technical Note #245:••• Since 0 is not a valid font size, the resource ID having 0 in the size field is used to provide only the name of the font: The name of the resource is the font name. For example, for a font named Griffin and numbered 200, the resource naming the font would have a resource ID of 25600 and the resource name 'Griffin'. Size 10 of that font would be stored in a resource numbered 25610. •••Refer to Figure 10.••• Figure 10–Resource ID for a Font The resource type 'FRSV' is reserved by the Font Manager; it identifies fonts used by the system. Fonts whose resource IDs are contained in a 'FRSV' resource 1 will not be removed from the system resource file by the Font/DA Mover. The format of a 'FRSV' resource is as follows: Number of bytes Contents 2 bytes Number of font resource IDs n * 2 bytes n font resource IDs æKY FMetricRec æFp Fonts.p æT RECORD æD FMetricRec = RECORD ascent: Fixed; {base line to top} descent: Fixed; {base line to bottom} leading: Fixed; {leading between lines} widMax: Fixed; {maximum character width} wTabHandle: Handle; {handle to font width table} END; æC æKY WidEntry æFp Fonts.p æT RECORD æD WidEntry = RECORD widStyle: INTEGER; {style entry applies to} END; æC æKY WidTable æFp Fonts.p æT RECORD æD WidTable = RECORD numWidths: INTEGER; {number of entries - 1} END; æC æKY AsscEntry æFp Fonts.p æT RECORD æD AsscEntry = RECORD fontSize: INTEGER; fontStyle: INTEGER; fontID: INTEGER; {font resource ID} END; æC æKY FontAssoc æFp Fonts.p æT RECORD æD FontAssoc = RECORD numAssoc: INTEGER; {number of entries - 1} END; æC æKY StyleTable æFp Fonts.p æT RECORD æD StyleTable = RECORD fontClass: INTEGER; offset: LONGINT; reserved: LONGINT; indexes: ARRAY [0..47] OF SignedByte; END; æC æKY NameTable æFp Fonts.p æT RECORD æD NameTable = RECORD stringCount: INTEGER; baseFontName: Str255; END; æC æKY KernPair æFp Fonts.p æT RECORD æD KernPair = RECORD kernFirst: CHAR; {1st character of kerned pair} kernSecond: CHAR; {2nd character of kerned pair} kernWidth: INTEGER; {kerning in 1pt fixed format} END; æC æKY KernEntry æFp Fonts.p æT RECORD æD KernEntry = RECORD kernLength: INTEGER; {length of this entry} kernStyle: INTEGER; {style the entry applies to} END; æC æKY KernTable æFp Fonts.p æT RECORD æD KernTable = RECORD numKerns: INTEGER; {number of kerning entries} END; æC æKY WidthTable æFp Fonts.p æT RECORD æD WidthTable = PACKED RECORD tabData: ARRAY [1..256] OF Fixed; {character widths} tabFont: Handle; {font record used to build table} sExtra: LONGINT; {space extra used for table} style: LONGINT; {extra due to style} fID: INTEGER; {font family ID} fSize: INTEGER; {font size request} face: INTEGER; {style (face) request} device: INTEGER; {device requested} inNumer: Point; {scale factors requested} inDenom: Point; {scale factors requested} aFID: INTEGER; {actual font family ID for table} fHand: Handle; {family record used to build up table} usedFam: BOOLEAN; {used fixed point family widths} aFace: Byte; {actual face produced} vOutput: INTEGER; {vertical scale output value} hOutput: INTEGER; {horizontal scale output value} vFactor: INTEGER; {vertical scale output value} hFactor: INTEGER; {horizontal scale output value} aSize: INTEGER; {actual size of actual font used} tabSize: INTEGER; {total size of table} END; æC »Global Width Tables Note: The extensions to the Font Manager described in the following paragraphs were originally documented in Inside Macintosh, Volume IV. As such, this information refers to the 128K ROMs and System file version 3.2 and later. The Font Manager communicates fractional character widths to QuickDraw via a global width table, a data structure allocated in the system heap. A handle to the global width table is returned by the FontMetrics procedure. The format of the global width table is follows: TYPE WidthTable = RECORD tabData: ARRAY[1..256] OF Fixed; { character widths} tabFont: Handle; {font record used to build table} sExtra: LONGINT; {space extra used for table} style: LONGINT; {extra due to style} fID: INTEGER; {font family ID} fSize: INTEGER; {font size request} face: INTEGER; {style (face) request} device: INTEGER; {device requested} inNumer: Point; {numerators of scaling factors} inDenom: Point; {denominators of scaling factors} aFID: INTEGER; {actual font family ID for table} fHand: handle; {family record used to build table} usedFam: BOOLEAN; {used fixed-point family widths} aFace: Byte; {actual face produced} vOutput: INTEGER; {vertical factor for expanding } { characters} hOutput: INTEGER; {horizontal factor for expanding } { characters} vFactor: INTEGER; {not used} hFactor: INTEGER; {horizontal factor for increasing } { character widths} aSize: INTEGER; {actual size of actual font used} tabSize: INTEGER {total size of table} END; TabData is an array containing a character width for each of the 255 possible characters in a font, plus one long word for the font’s missing symbol. The widths are stored in the standard 32-bit fixed-point format. If a character is missing, its entry contains the width of the missing symbol. (For efficiency, the Font Manager will store up to 12 recently used global width tables.) InNumer and inDenom contain the vertical and horizontal scaling factors copied from the font input record. Scaling is effected in two ways: by expanding characters of the chosen font and by artificially increasing the widths of the chosen font in the width table. HOutput and vOutput give the factors by which characters are to be expanded horizontally and vertically. HFactor is the factor by which the widths of the chosen font, after stylistic variations, have been increased. (VFactor is not used.) Thus, multiplying hOutput and vOutput by hFactor and vFactor gives the true font scaling; the product of hOutput and an entry in the width table is that character’s true scaled width. HOutput,vOutput, hFactor, and vFactor are all 16-bit fixed-point numbers, with an integer part in the high-order byte and a fractional part in the low-order byte. If font scaling has been enabled, hFactor and vFactor both have a value of 1. In any case, hOutput, vOutput, hFactor, and vFactor are adjusted so that the values of hFactor and vFactor lie between 1 and 2, including 1. Assembly-language note: A handle to the global width table is contained in the global variable WidthTabHandle. A pointer to the table is contained in the global variable WidthPtr; it’s reliable immediately after a call to FMSwapFont but, like all pointers, may become invalid after a call to the Memory Manager. The global variable WidthListHand is a handle to a list of handles to up to 12 recently-used width tables. You can scan this list, looking for width tables that match the family number, size, and style of the font you wish to measure. If you reach a width handle that’s equal to –1, that width table is invalid, and you must make an FMSwapFont call to get a valid one. When you reach a handle that’s zero, you’ve reached the end of the list. You should not use the global width table when special international interface software is being used to accommodate non-Roman alphabets. You can recognize such software by looking at the global variable IntlSpec; if it’s greater than 0, special international software is installed. If your application uses non-Roman alphabets, write to Developer Technical Support Apple Computer, Inc. 20525 Mariani Avenue, M/S 75-3T Cupertino, CA 95014 for the latest version of the International Utilities Package, which will be extended to handle non-Roman alphabets. æKY FamRec æFp Fonts.p æT RECORD æD FamRec = RECORD ffFlags: INTEGER; {flags for family} ffFamID: INTEGER; {family ID number} ffFirstChar: INTEGER; {ASCII code of 1st character} ffLastChar: INTEGER; {ASCII code of last character} ffAscent: INTEGER; {maximum ascent for 1pt font} ffDescent: INTEGER; {maximum descent for 1pt font} ffLeading: INTEGER; {maximum leading for 1pt font} ffWidMax: INTEGER; {maximum widMax for 1pt font} ffWTabOff: LONGINT; {offset to width table} ffKernOff: LONGINT; {offset to kerning table} ffStylOff: LONGINT; {offset to style mapping table} ffProperty: ARRAY [1..9] OF INTEGER; {style property info} ffIntl: ARRAY [1..2] OF INTEGER; {for international use} ffVersion: INTEGER; {version number} END; æC »Family Records Note: The extensions to the Font Manager described in the following paragraphs were originally documented in Inside Macintosh, Volume IV. As such, this information refers to the 128K ROMs and System file version 3.2 and later. Assembly-language note: The global variable LastFOND is a handle to the last family record used. You can read the contents of the family record by using this handle. You should not alter the contents of this record. The data type for a family record is as follows: TYPE FamRec = RECORD ffFlags: INTEGER; {flags for family} ffFamID: INTEGER; {family ID number} ffFirstChar: INTEGER; {ASCII code of the first character} ffLastChar: INTEGER; {ASCII code of the last character} ffAscent: INTEGER; {maximum ascent for 1-pt.font} ffDescent: INTEGER; {maximum descent for 1-pt.font} ffLeading: INTEGER; {maximum leading for 1-pt.font} ffWidMax: INTEGER; {maximum width for 1-pt.font} ffWTabOff: LONGINT; {offset to width table} ffKernOff: LONGINT; {offset to kerning table} ffStylOff: LONGINT; {offset to style-mapping table} ffProperty: ARRAY[1..9] OF INTEGER; {style property info} ffIntl: ARRAY[1..2] OF INTEGER; {reserved} ffVersion: INTEGER; {version number} { ffAssoc: FontAssoc;} {font association table} { ffWidthTab: WidTable;} {width table} { ffStyTab: StyleTable;}{style-mapping table} { ffKernTab: KernTable;} {kerning table} END; Note: The variable-length arrays appear as comments because they’re not valid Pascal syntax; they’re used only as conceptual aids. This version of the FamRec is accurate for Volume IV; the extensions to the FamRec made in Volume V are not included here. The ffFlags field defines general characteristics of the font family, as follows: Bit Meaning 0 Set if there’s an image-height table 1 Set if there’s a character-width table 2–11 Reserved (should be zero) 12 Set to ignore FractEnable when deciding whether to use fixed-point values for stylistic variations (see bit 13), clear to treat FractEnable as usual 13 Set to use integer extra width for stylistic variations, clear to compute fixed-point extra width from the family style-mapping table when FractEnable is TRUE 14 Set if family fractional-width table is not used, clear if table is used 15 Set for fixed-width font, clear for proportional font The values in the ffAscent, ffDescent, ffLeading, and ffWidMax describe the maximum dimensions of the family as they would be for a hypothetical one-point font to be scaled up. They use a special 16-bit fixed-point format with an integer part in the high-order 4 bits and a fractional part in the low-order 12 bits. The FontMetrics procedure calculates the true values by multiplying this number by the actual point size. The ffWTabOff, ffKernOff, and ffStylOff fields are offsets from the top of the record to the start of the width table, kerning table, and style-mapping table, respectively; if any of these fields is zero, the corresponding table does not exist. The ffProperty field is the family style-property table, shown in Figure 11. •••Refer to Figure 11.••• Figure 11–Family Style-Property Table Each entry is a 16-bit fixed-point number with a signed integer part in the high-order 4 bits and a fractional part in the low-order 12 bits. These numbers are used to calculate the amount of extra width for special stylistic variations; each of these values is multiplied by the point size of the font actually being used. If the font already exists for a given style, the value in its field is ignored. The ffAssoc field contains the font association table. This table, shown in Figure 12, is used to match a given font size and style combination with the resource ID of an actual font. •••Refer to Figure 12.••• Figure 12–Font Association Table Note: In order to reduce search time, the Font Manager requires that the entries be sorted according to the fontSize field, with the smallest sizes first. If multiple fonts from the same family, the plain (roman) fonts come first. The Font Manager is optimized to look first for 'NFNT' resources, then 'FONT' resources. Each entry in the font association table has the format shown in Figure 13. •••Refer to Figure 13.••• Figure 13–Font Association Table Entry The font association table is followed by the family character-width table. As shown in Figure 14, this table is actually a number of width tables (since a font family may include numerous styles). •••Refer to Figure 14.••• Figure 14–Family Character-Width Table Each character-width table is preceded by a style code; the low-order byte of this word specifies stylistic variations (see Figure 15). The widths in each table are for a hypothetical one-point font; the actual values for the characters are calculated by multiplying these widths by the font size. The widths in this table are stored in a 16-bit fixed-point format with an unsigned integer part in the high-order 4 bits and a fractional part in the low-order 12 bits. •••Refer to Figure 15.••• Figure 15–Style Codes The style-mapping table and its associated tables are used by the LaserWriter driver and are described in the Apple LaserWriter Reference. The kerning table, like the family character-width table, is actually a number of kerning tables (see Figure 16). •••Refer to Figure 16.••• Figure 16–Kerning Table Each kerning table is preceded by a style code; stored in the low-order byte of the word, this style information has the same format shown in Figure 15 above. The number of entries in the table follows the style word (see Figure 17). •••Refer to Figure 17.••• Figure 17–Structure of a Kerning Table The entries in each kerning table (shown in Figure 18) consist of a pair of characters followed by a kerning offset for a hypothetical one-point font. This value, represented by an integer part in the high-order 4 bits and a fractional part in the low-order 12 bits, is multiplied by the size of the font to obtain the actual offset. •••Refer to Figure 18.••• Figure 18–Kerning Table Entry Note: The extensions to the Font Manager described in the following paragraphs were originally documented in Inside Macintosh, Volume V. As such, this information refers to the Macintosh SE and Macintosh II ROMs and System file version 4.1 and later. For Macintosh II only, bits 8 and 9 of the font style word within each font association table specify the font depth; they must contain the same value as bits 2 and 3 of the fontType field of the font record. All other undefined bits remain 0. A font family is stored as a resource of type 'FOND', and with the Macintosh II, it’s format has been extended. The new format is the following (with extension fields indicated by asterisks): Number of bytes Contents 2 bytes FONDFlags field of family record 2 bytes FONDFamID field of family record 2 bytes FONDFirst field of family record 2 bytes FONDLast field of family record 2 bytes FONDAscent field of family record 2 bytes FONDDescent field of family record 2 bytes FONDLeading field of family record 2 bytes FONDWidMax field of family record 4 bytes FONDWTabOff of family record 4 bytes FONDKernOff of family record 4 bytes FONDStylOff of family record 24 bytes FONDProperty field of family record 4 bytes FONDIntl field of family record 2 bytes *Version number ($02) m bytes FONDAssoc field of family record (variable length) 2 bytes *Number of offsets minus 1 4 bytes *Offset to bounding box table n bytes *Bounding box table p bytes FONDWidTable field of family record (variable length) q bytes FONDStylTab field of family record (variable length) r bytes FONDKerntab field of family record (variable length) The bounding box table has an entry for each style available in the family. The table as a whole has this form: Number of bytes Contents 2 bytes Number of entries minus 1 10 bytes First entry 10 bytes Second entry . . . Each bounding box entry has this form, giving the bounding box position with respect to the origin of the characters: Number of bytes Contents 2 bytes Style word 2 bytes Lower left x coordinate 2 bytes Lower left y coordinate 2 bytes Upper right x coordinate 2 bytes Upper right y coordinate Note: The extensions to the Font Manager described in the following paragraphs were originally documented in Inside Macintosh, Volume IV. As such, this information refers to the 128K ROMs and System file version 3.2 and later. æKY InitFonts æFp Fonts.p æT PROCEDURE æTN A8FE æD PROCEDURE InitFonts; INLINE $A8FE; æDT InitFonts(paramList); æMM æRT 72 æRI I-222, P-31, 95, 101, 107, 112, 118, 174 æC InitFonts initializes the Font Manager. If the system font isn’t already in memory, InitFonts reads it into memory. Call this procedure once before all other Font Manager routines or any Toolbox routine that will call the Font Manager. æKY GetFontName æFp Fonts.p æT PROCEDURE æTN A8FF æD PROCEDURE GetFontName(familyID: INTEGER;VAR theName: Str255); INLINE $A8FF; æDT GetFontName(familyID,theName); æMM æRT 191 æRI I-223 æC Warning: Before returning, the routines in this section issue the Resource Manager call SetResLoad(TRUE). If your program previously called SetResLoad(FALSE) and you still want that to be in effect after calling one of these Font Manager routines, you’ll have to call SetResLoad(FALSE) again. PROCEDURE GetFontName (fontNum: INTEGER; VAR theName: Str255); Assembly-language note: The macro you invoke to call GetFontName from assembly language is named _GetFName. GetFontName returns in theName the name of the font having the font number fontNum. If there’s no such font, GetFontName returns the empty string. æKY GetFNum æFp Fonts.p æT PROCEDURE æTN A900 æD PROCEDURE GetFNum(theName: Str255;VAR familyID: INTEGER); INLINE $A900; æDT GetFNum(theName,familyID); æMM æRT 191 æRI I-223 æC Warning: Before returning, the routines in this section issue the Resource Manager call SetResLoad(TRUE). If your program previously called SetResLoad(FALSE) and you still want that to be in effect after calling one of these Font Manager routines, you’ll have to call SetResLoad(FALSE) again. GetFNum returns in theNum the font number for the font having the given fontName. If there’s no such font, GetFNum returns 0. æKY RealFont æFp Fonts.p æT FUNCTION æTN A902 æD FUNCTION RealFont(fontNum: INTEGER;size: INTEGER): BOOLEAN; INLINE $A902; æDT myVariable := RealFont(fontNum,size); æMM æRI I-223 æC Warning: Before returning, the routines in this section issue the Resource Manager call SetResLoad(TRUE). If your program previously called SetResLoad(FALSE) and you still want that to be in effect after calling one of these Font Manager routines, you’ll have to call SetResLoad(FALSE) again. RealFont returns TRUE if the font having the font number fontNum is available in the given size in a resource file, or FALSE if the font has to be scaled to that size. Note: RealFont will always return FALSE if you pass applFont in fontNum. To find out if the application font is available in a particular size, call GetFontName and then GetFNum to get the actual font number for the application font, and then call RealFont with that number. æKY SetFontLock æFp Fonts.p æT PROCEDURE æTN A903 æD PROCEDURE SetFontLock(lockFlag: BOOLEAN); INLINE $A903; æDT SetFontLock(lockFlag); æMM æRI I-223 æC SetFontLock applies to the font in which text was most recently drawn. If lockFlag is TRUE, SetFontLock makes the font unpurgeable (reading it into memory if it isn’t already there). If lockFlag is FALSE, it releases the memory occupied by the font (by calling the Resource Manager procedure ReleaseResource). Since fonts are normally purgeable, this procedure is useful for making a font temporarily unpurgeable. æKY FMSwapFont æFp Fonts.p æT FUNCTION æTN A901 æD FUNCTION FMSwapFont(inRec: FMInput): FMOutPtr; INLINE $A901; { FMSwapFont returns a pointer to an FMOutput record containing the size, style, and other information about an adapted version of the font requested in the given FMInput record. (FMInput and FMOutput records are explained in the following section.) FMSwapFont is called by QuickDraw every time a QuickDraw routine that does anything with text is used. If you want to call FMSwapFont yourself, you must build an FMInput record and then use the returned pointer to access the resulting FMOutput record. } æDT myVariable := FMSwapFont(inRec); æMM æRI I-223 æC The following low-level routine is called by QuickDraw and won’t normally be used by an application directly, but it may be of interest to advanced programmers who want to bypass the QuickDraw routines that deal with text. FUNCTION FMSwapFont (inRec: FMInput) : FMOutPtr; FMSwapFont returns a pointer to a font output record containing the size, style, and other information about an adapted version of the font requested in the given font input record. (Font input and output records are explained in the following section.) FMSwapFont is called by QuickDraw every time a QuickDraw routine that does anything with text is used. If you want to call FMSwapFont yourself, you must build a font input record and then use the pointer returned by FMSwapFont to access the resulting font output record. æKY SetFScaleDisable æFp Fonts.p æT PROCEDURE æTN A834 æD PROCEDURE SetFScaleDisable(fscaleDisable: BOOLEAN); INLINE $A834; æDT SetFScaleDisable(fscaleDisable); æRI IV-32 æC Note: The extensions to the Font Manager described in the following paragraphs were originally documented in Inside Macintosh, Volume IV. As such, this information refers to the 128K ROMs and System file version 3.2 and later. SetFScaleDisable lets you disable or enable font scaling. If fScaleDisable is TRUE, font scaling is disabled and the Font Manager returns an unscaled font with more space around the characters; if it’s FALSE, the Font Manager scales fonts. To ensure compatibility with existing applications, the Font Manager defaults to scaling fonts. Assembly-language note: All programmers should use the SetFScaleDisable procedure to disable and enable font scaling. In particular, setting the global variable FScaleDisable is insufficient. æKY FontMetrics æFp Fonts.p æT PROCEDURE æTN A835 æD PROCEDURE FontMetrics(theMetrics: FMetricRec); INLINE $A835; æDT FontMetrics(theMetrics); æMM æRI IV-32 æC Note: The extensions to the Font Manager described in the following paragraphs were originally documented in Inside Macintosh, Volume IV. As such, this information refers to the 128K ROMs and System file version 3.2 and later. To improve the speed and readability of text display in your application, use the SetFractEnable and SetFScaleDisable procedures to enable fractional character widths and disable font scaling. Certain applications do not work properly when fractional character widths are used and font scaling is disabled, so these features are turned off by default. The FontMetrics function is much like QuickDraw’s GetFontInfo function except that it returns fixed-point values, letting you draw characters in more precise locations on the screen. If there’s a 'FOND' resource associated with the most recently drawn font, making the font resource purgeable or unpurgeable with the SetFontLock procedure will make the 'FOND' resource resource purgeable or unpurgeable as well. PROCEDURE FontMetrics (VAR theMetrics: FMetricRec); FontMetrics is similar to the QuickDraw procedure GetFontInfo except that it returns fixed-point values for greater accuracy in high-resolution printing. The FMetricRec data structure is defined as follows: TYPE FMetricRec = RECORD ascent: Fixed; {ascent} descent: Fixed; {descent} leading: Fixed; {leading} widMax: Fixed; {maximum character width} wTabHandle: Handle; {handle to global width table} END; Ascent, descent, leading, and widMax are identical in function to their counterparts in GetFontInfo. WTabHandle is a handle to the global width table (described below). æKY SetFractEnable æFp Fonts.p æT PROCEDURE æD PROCEDURE SetFractEnable(fractEnable: BOOLEAN); æDT SetFractEnable(fractEnable); æRT 72 æRI V-180 æC Note: The extensions to the Font Manager described in the following paragraphs were originally documented in Inside Macintosh, Volume IV. As such, this information refers to the 128K ROMs and System file version 3.2 and later. SetFractEnable lets you enable or disable fractional character widths. If fractEnable is TRUE, fractional character widths are enabled; if it’s FALSE, the Font Manager uses integer widths. To ensure compatibility with existing applications, fractional character widths are disabled by default. SetFractEnable, which was not in the 128K ROM (but was available in the Pascal interfaces) has been added to both the Macintosh SE and Macintosh II ROMs. Assembly-language note: Assembly-language programmers should call SetFractEnable rather than change the value of the global variable FractEnable. æKY GestaltEqu.p æKL Gestalt NewGestalt ReplaceGestalt gestalt32BitAddressing gestalt32BitCapable gestalt32BitQD gestalt32BitSysZone gestalt68000 gestalt68010 gestalt68020 gestalt68030 gestalt68030MMU gestalt68040 gestalt68040FPU gestalt68040MMU gestalt68851 gestalt68881 gestalt68882 gestalt8BitQD gestaltAddressingModeAttr gestaltAliasMgrAttr gestaltAliasMgrPresent gestaltAMU gestaltAppleEventsAttr gestaltAppleEventsPresent gestaltAppleTalkVersion gestaltAUXVersion gestaltClassic gestaltCTBVersion gestaltDBAccessMgrAttr gestaltDBAccessMgrPresent gestaltDupSelectorErr gestaltEditionMgrAttr gestaltEditionMgrPresent gestaltElmerISOKbd gestaltElmerKbd gestaltExtADBKbd gestaltExtendedTimeMgr gestaltExtISOADBKbd gestaltFolderMgrAttr gestaltFolderMgrPresent gestaltFontMgrAttr gestaltFPUType gestaltHardwareAttr gestaltHasASC gestaltHasParityCapability gestaltHasSCC gestaltHasSCSI gestaltHasVIA1 gestaltHasVIA2 gestaltHelpMgrAttr gestaltHelpMgrPresent gestaltIPCSupport gestaltKeyboardType gestaltLaunchCanReturn gestaltLaunchControl gestaltLaunchFullFileSpec gestaltLocationErr gestaltLogicalPageSize gestaltLogicalRAMSize gestaltLowMemorySize gestaltMac512KE gestaltMacAndPad gestaltMachineType gestaltMacII gestaltMacIIci gestaltMacIIcx gestaltMacIIfx gestaltMacIIx gestaltMacKbd gestaltMacPlus gestaltMacPlusKbd gestaltMacSE gestaltMacSE030 gestaltMacXL gestaltMiscAttr gestaltMMUType gestaltNoFPU gestaltNoMMU gestaltNotificationMgrAttr gestaltNotificationPresent gestaltOriginalQD gestaltOSAttr gestaltOutlineFonts gestaltParityAttr gestaltParityEnabled gestaltPartialRsrcs gestaltPhysicalRAMSize gestaltPMgrCPUIdle gestaltPMgrExists gestaltPMgrSCC gestaltPMgrSound gestaltPortable gestaltPowerMgrAttr gestaltPPCSupportsDontCare gestaltPPCSupportsIncomming gestaltPPCSupportsOutGoing gestaltPPCSupportsRealTime gestaltPPCSupportsStoreAndForward gestaltPPCToolboxAttr gestaltPPCToolboxPresent gestaltProcessorType gestaltPrtblADBKbd gestaltPrtblISOKbd gestaltQuickdrawVersion gestaltRealTempMemory gestaltResourceMgrAttr gestaltRevisedTimeMgr gestaltROMSize gestaltROMVersion gestaltScriptCount gestaltScriptMgrVersion gestaltScrollingThrottle gestaltSoundAttr gestaltStandardTimeMgr gestaltStdADBKbd gestaltStdISOADBKbd gestaltStereoCapability gestaltStereoMixing gestaltSysDebuggerSupport gestaltSystemVersion gestaltSysZoneGrowable gestaltTE1 gestaltTE2 gestaltTE3 gestaltTE4 gestaltTempMemSupport gestaltTempMemTracked gestaltTextEditVersion gestaltTimeMgrVersion gestaltUndefSelectorErr gestaltUnknownErr gestaltVersion gestaltVMAttr gestaltVMPresent æKY gestaltUnknownErr æFp GestaltEqu.p æT CONST æD { *********************** * Gestalt error codes *********************** } gestaltUnknownErr = -5550; { value returned if Gestalt doesn't know the answer } æC æKY gestaltUndefSelectorErr æFp GestaltEqu.p æT CONST æD gestaltUndefSelectorErr = -5551; { undefined selector was passed to Gestalt } æC æKY gestaltDupSelectorErr æFp GestaltEqu.p æT CONST æD gestaltDupSelectorErr = -5552; { tried to add an entry that already existed } æC æKY gestaltLocationErr æFp GestaltEqu.p æT CONST æD gestaltLocationErr = -5553; { gestalt function ptr wasn't in sysheap } æC æKY gestaltVersion æFp GestaltEqu.p æT CONST æD { ************************* * Environment Selectors ************************* } gestaltVersion = 'vers'; { gestalt version } æC æKY gestaltAddressingModeAttr æFp GestaltEqu.p æT CONST æD gestaltAddressingModeAttr = 'addr'; { addressing mode attributes } æC æKY gestalt32BitAddressing æFp GestaltEqu.p æT CONST æD gestalt32BitAddressing = 0; { using 32-bit addressing mode } æC æKY gestalt32BitSysZone æFp GestaltEqu.p æT CONST æD gestalt32BitSysZone = 1; { 32-bit compatible system zone } æC æKY gestalt32BitCapable æFp GestaltEqu.p æT CONST æD gestalt32BitCapable = 2; { Machine is 32-bit capable } æC æKY gestaltAliasMgrAttr æFp GestaltEqu.p æT CONST æD gestaltAliasMgrAttr = 'alis'; { Alias Mgr Attributes } æC æKY gestaltAliasMgrPresent æFp GestaltEqu.p æT CONST æD gestaltAliasMgrPresent = 0; { True if the Alias Mgr is present } æC æKY gestaltAppleTalkVersion æFp GestaltEqu.p æT CONST æD gestaltAppleTalkVersion = 'atlk'; { appletalk version } æC æKY gestaltAUXVersion æFp GestaltEqu.p æT CONST æD gestaltAUXVersion = 'a/ux'; {a/ux version, if present } æC æKY gestaltCTBVersion æFp GestaltEqu.p æT CONST æD gestaltCTBVersion = 'ctbv'; { CommToolbox version } æC æKY gestaltDBAccessMgrAttr æFp GestaltEqu.p æT CONST æD gestaltDBAccessMgrAttr = 'dbac'; { Database Access Mgr attributes } æC æKY gestaltDBAccessMgrPresent æFp GestaltEqu.p æT CONST æD gestaltDBAccessMgrPresent = 0; { True if Database Access Mgr present } æC æKY gestaltEditionMgrAttr æFp GestaltEqu.p æT CONST æD gestaltEditionMgrAttr = 'edtn'; { Edition Mgr attributes } æC æKY gestaltEditionMgrPresent æFp GestaltEqu.p æT CONST æD gestaltEditionMgrPresent = 0; { True if Edition Mgr present } æC æKY gestaltAppleEventsAttr æFp GestaltEqu.p æT CONST æD gestaltAppleEventsAttr = 'evnt'; { Apple Events attributes } æC æKY gestaltAppleEventsPresent æFp GestaltEqu.p æT CONST æD gestaltAppleEventsPresent = 0; { True if Apple Events present } æC æKY gestaltFolderMgrAttr æFp GestaltEqu.p æT CONST æD gestaltFolderMgrAttr = 'fold'; { Folder Mgr attributes } æC æKY gestaltFolderMgrPresent æFp GestaltEqu.p æT CONST æD gestaltFolderMgrPresent = 0; { True if Folder Mgr present } æC æKY gestaltFontMgrAttr æFp GestaltEqu.p æT CONST æD gestaltFontMgrAttr = 'font'; { Font Mgr attributes } æC æKY gestaltOutlineFonts æFp GestaltEqu.p æT CONST æD gestaltOutlineFonts = 0; { True if Outline Fonts supported } æC æKY gestaltFPUType æFp GestaltEqu.p æT CONST æD gestaltFPUType = 'fpu '; { fpu type } æC æKY gestaltNoFPU æFp GestaltEqu.p æT CONST æD gestaltNoFPU = 0; { no FPU } æC æKY gestalt68881 æFp GestaltEqu.p æT CONST æD gestalt68881 = 1; { 68881 FPU } æC æKY gestalt68882 æFp GestaltEqu.p æT CONST æD gestalt68882 = 2; { 68882 FPU } æC æKY gestalt68040FPU æFp GestaltEqu.p æT CONST æD gestalt68040FPU = 3; { 68040 built-in FPU } æC æKY gestaltHardwareAttr æFp GestaltEqu.p æT CONST æD gestaltHardwareAttr = 'hdwr'; { hardware attributes } æC æKY gestaltHasVIA1 æFp GestaltEqu.p æT CONST æD gestaltHasVIA1 = 0; { VIA1 exists } æC æKY gestaltHasVIA2 æFp GestaltEqu.p æT CONST æD gestaltHasVIA2 = 1; { VIA2 exists } æC æKY gestaltHasASC æFp GestaltEqu.p æT CONST æD gestaltHasASC = 3; { Apple Sound Chip exists } æC æKY gestaltHasSCC æFp GestaltEqu.p æT CONST æD gestaltHasSCC = 4; { SCC exists } æC æKY gestaltHasSCSI æFp GestaltEqu.p æT CONST æD gestaltHasSCSI = 7; { SCSI exists } æC æKY gestaltHelpMgrAttr æFp GestaltEqu.p æT CONST æD gestaltHelpMgrAttr = 'help'; { Help Mgr Attributes } æC æKY gestaltHelpMgrPresent æFp GestaltEqu.p æT CONST æD gestaltHelpMgrPresent = 0; { true if help mgr is present } æC æKY gestaltKeyboardType æFp GestaltEqu.p æT CONST æD gestaltKeyboardType = 'kbd '; { keyboard type } æC æKY gestaltMacKbd æFp GestaltEqu.p æT CONST æD gestaltMacKbd = 1; æC æKY gestaltMacAndPad æFp GestaltEqu.p æT CONST æD gestaltMacAndPad = 2; æC æKY gestaltMacPlusKbd æFp GestaltEqu.p æT CONST æD gestaltMacPlusKbd = 3; æC æKY gestaltExtADBKbd æFp GestaltEqu.p æT CONST æD gestaltExtADBKbd = 4; æC æKY gestaltStdADBKbd æFp GestaltEqu.p æT CONST æD gestaltStdADBKbd = 5; æC æKY gestaltPrtblADBKbd æFp GestaltEqu.p æT CONST æD gestaltPrtblADBKbd = 6; æC æKY gestaltPrtblISOKbd æFp GestaltEqu.p æT CONST æD gestaltPrtblISOKbd = 7; æC æKY gestaltStdISOADBKbd æFp GestaltEqu.p æT CONST æD gestaltStdISOADBKbd = 8; æC æKY gestaltExtISOADBKbd æFp GestaltEqu.p æT CONST æD gestaltExtISOADBKbd = 9; æC æKY gestaltElmerKbd æFp GestaltEqu.p æT CONST æD gestaltElmerKbd = 10; æC æKY gestaltElmerISOKbd æFp GestaltEqu.p æT CONST æD gestaltElmerISOKbd = 11; æC æKY gestaltLowMemorySize æFp GestaltEqu.p æT CONST æD gestaltLowMemorySize = 'lmem'; { size of low memory area } æC æKY gestaltLogicalRAMSize æFp GestaltEqu.p æT CONST æD gestaltLogicalRAMSize = 'lram'; { logical ram size } æC æKY gestaltMiscAttr æFp GestaltEqu.p æT CONST æD gestaltMiscAttr = 'misc'; { miscellaneous attributes } æC æKY gestaltScrollingThrottle æFp GestaltEqu.p æT CONST æD gestaltScrollingThrottle = 0; { true if scrolling throttle on } æC æKY gestaltMMUType æFp GestaltEqu.p æT CONST æD gestaltMMUType = 'mmu '; { mmu type } æC æKY gestaltNoMMU æFp GestaltEqu.p æT CONST æD gestaltNoMMU = 0; { no MMU } æC æKY gestaltAMU æFp GestaltEqu.p æT CONST æD gestaltAMU = 1; { address management unit } æC æKY gestalt68851 æFp GestaltEqu.p æT CONST æD gestalt68851 = 2; { 68851 PMMU } æC æKY gestalt68030MMU æFp GestaltEqu.p æT CONST æD gestalt68030MMU = 3; { 68030 built-in MMU } æC æKY gestalt68040MMU æFp GestaltEqu.p æT CONST æD gestalt68040MMU = 4; { 68040 built-in MMU } æC æKY gestaltNotificationMgrAttr æFp GestaltEqu.p æT CONST æD gestaltNotificationMgrAttr = 'nmgr'; { notification manager attributes } æC æKY gestaltNotificationPresent æFp GestaltEqu.p æT CONST æD gestaltNotificationPresent = 0; { notification manager exists } æC æKY gestaltOSAttr æFp GestaltEqu.p æT CONST æD gestaltOSAttr = 'os '; { o/s attributes } æC æKY gestaltSysZoneGrowable æFp GestaltEqu.p æT CONST æD gestaltSysZoneGrowable = 0; { system heap is growable } æC æKY gestaltLaunchCanReturn æFp GestaltEqu.p æT CONST æD gestaltLaunchCanReturn = 1; { can return from launch } æC æKY gestaltLaunchFullFileSpec æFp GestaltEqu.p æT CONST æD gestaltLaunchFullFileSpec = 2; { can launch from full file spec } æC æKY gestaltLaunchControl æFp GestaltEqu.p æT CONST æD gestaltLaunchControl = 3; { launch control support available } æC æKY gestaltTempMemSupport æFp GestaltEqu.p æT CONST æD gestaltTempMemSupport = 4; { temp memory support } æC æKY gestaltRealTempMemory æFp GestaltEqu.p æT CONST æD gestaltRealTempMemory = 5; { temp memory handles are real } æC æKY gestaltTempMemTracked æFp GestaltEqu.p æT CONST æD gestaltTempMemTracked = 6; { temporary memory handles are tracked } æC æKY gestaltIPCSupport æFp GestaltEqu.p æT CONST æD gestaltIPCSupport = 7; { IPC support is present } æC æKY gestaltSysDebuggerSupport æFp GestaltEqu.p æT CONST æD gestaltSysDebuggerSupport = 8; { system debugger support is present } æC æKY gestaltLogicalPageSize æFp GestaltEqu.p æT CONST æD gestaltLogicalPageSize = 'pgsz'; { logical page size } æC æKY gestaltPowerMgrAttr æFp GestaltEqu.p æT CONST æD gestaltPowerMgrAttr = 'powr'; { power manager attributes } æC æKY gestaltPMgrExists æFp GestaltEqu.p æT CONST æD gestaltPMgrExists = 0; æC æKY gestaltPMgrCPUIdle æFp GestaltEqu.p æT CONST æD gestaltPMgrCPUIdle = 1; æC æKY gestaltPMgrSCC æFp GestaltEqu.p æT CONST æD gestaltPMgrSCC = 2; æC æKY gestaltPMgrSound æFp GestaltEqu.p æT CONST æD gestaltPMgrSound = 3; æC æKY gestaltPPCToolboxAttr æFp GestaltEqu.p æT CONST æD gestaltPPCToolboxAttr = 'ppc '; { PPC toolbox attributes } æC æKY gestaltPPCToolboxPresent æFp GestaltEqu.p æT CONST æD { * PPC will return the combination of following bit fields. * e.g. gestaltPPCSupportsRealTime +gestaltPPCSupportsIncomming + gestaltPPCSupportsOutGoing * indicates PPC is cuurently is only supports real time delivery * and both icoming and outgoing network sessions are allowed. * By default local real time delivery is supported as long as PPCInit has been called. } gestaltPPCToolboxPresent = $0000; { PPC Toolbox is present Requires PPCInit to be called } æC æKY gestaltPPCSupportsRealTime æFp GestaltEqu.p æT CONST æD gestaltPPCSupportsRealTime = $1000; { PPC Supports real-time delivery } æC æKY gestaltPPCSupportsStoreAndForward æFp GestaltEqu.p æT CONST æD gestaltPPCSupportsStoreAndForward = $2000; { PPC Store and Forward delivery } æC æKY gestaltPPCSupportsDontCare æFp GestaltEqu.p æT CONST æD gestaltPPCSupportsDontCare = $4000; { PPC Supports Specification of Don't care } æC æKY gestaltPPCSupportsIncomming æFp GestaltEqu.p æT CONST æD gestaltPPCSupportsIncomming = $0001; { PPC will deny incomming network requests } æC æKY gestaltPPCSupportsOutGoing æFp GestaltEqu.p æT CONST æD gestaltPPCSupportsOutGoing = $0002; { PPC will deny outgoing network requests } æC æKY gestaltProcessorType æFp GestaltEqu.p æT CONST æD gestaltProcessorType = 'proc'; { processor type } æC æKY gestalt68000 æFp GestaltEqu.p æT CONST æD gestalt68000 = 1; æC æKY gestalt68010 æFp GestaltEqu.p æT CONST æD gestalt68010 = 2; æC æKY gestalt68020 æFp GestaltEqu.p æT CONST æD gestalt68020 = 3; æC æKY gestalt68030 æFp GestaltEqu.p æT CONST æD gestalt68030 = 4; æC æKY gestalt68040 æFp GestaltEqu.p æT CONST æD gestalt68040 = 5; æC æKY gestaltParityAttr æFp GestaltEqu.p æT CONST æD gestaltParityAttr = 'prty'; { parity attributes } æC æKY gestaltHasParityCapability æFp GestaltEqu.p æT CONST æD gestaltHasParityCapability = 0; { has ability to check parity } æC æKY gestaltParityEnabled æFp GestaltEqu.p æT CONST æD gestaltParityEnabled = 1; { parity checking enabled } æC æKY gestaltQuickdrawVersion æFp GestaltEqu.p æT CONST æD gestaltQuickdrawVersion = 'qd '; { quickdraw version } æC æKY gestaltOriginalQD æFp GestaltEqu.p æT CONST æD gestaltOriginalQD = $000; { original 1-bit QD <3.2> } æC æKY gestalt8BitQD æFp GestaltEqu.p æT CONST æD gestalt8BitQD = $100; { 8-bit color QD <3.2> } æC æKY gestalt32BitQD æFp GestaltEqu.p æT CONST æD gestalt32BitQD = $200; { 32-bit color QD <3.2> } æC æKY gestaltPhysicalRAMSize æFp GestaltEqu.p æT CONST æD gestaltPhysicalRAMSize = 'ram '; { physical RAM size } æC æKY gestaltResourceMgrAttr æFp GestaltEqu.p æT CONST æD gestaltResourceMgrAttr = 'rsrc'; { Resource Mgr attributes } æC æKY gestaltPartialRsrcs æFp GestaltEqu.p æT CONST æD gestaltPartialRsrcs = 0; { True if partial resources exist } æC æKY gestaltScriptMgrVersion æFp GestaltEqu.p æT CONST æD gestaltScriptMgrVersion = 'scri'; { Script Manager version number <08/05/89 pke> } æC æKY gestaltScriptCount æFp GestaltEqu.p æT CONST æD gestaltScriptCount = 'scr#'; { number of active script systems <08/05/89 pke> } æC æKY gestaltSoundAttr æFp GestaltEqu.p æT CONST æD gestaltSoundAttr = 'snd '; { sound attributes } æC æKY gestaltStereoCapability æFp GestaltEqu.p æT CONST æD gestaltStereoCapability = 0; { sound hardware has stereo capability } æC æKY gestaltStereoMixing æFp GestaltEqu.p æT CONST æD gestaltStereoMixing = 1; { stereo mixing on external speaker } æC æKY gestaltTextEditVersion æFp GestaltEqu.p æT CONST æD gestaltTextEditVersion = 'te '; { TextEdit version number <08/05/89 pke> } æC æKY gestaltTE1 æFp GestaltEqu.p æT CONST æD gestaltTE1 = 1; { TextEdit in MacIIci ROM <8Aug89smb> } æC æKY gestaltTE2 æFp GestaltEqu.p æT CONST æD gestaltTE2 = 2; { TextEdit with 6.0.4 Script Systems on MacIIci (Script bug fixes for MacIIci) <8Aug89smb> } æC æKY gestaltTE3 æFp GestaltEqu.p æT CONST æD gestaltTE3 = 3; { TextEdit with 6.0.4 Script Systems all but MacIIci <8Aug89smb> } æC æKY gestaltTE4 æFp GestaltEqu.p æT CONST æD { **** Following is for System 7.0 Only **** } gestaltTE4 = 4; { TextEdit in System 7.0} æC æKY gestaltTimeMgrVersion æFp GestaltEqu.p æT CONST æD gestaltTimeMgrVersion = 'tmgr'; { time mgr version } æC æKY gestaltStandardTimeMgr æFp GestaltEqu.p æT CONST æD gestaltStandardTimeMgr = 1; { standard time mgr is present } æC æKY gestaltRevisedTimeMgr æFp GestaltEqu.p æT CONST æD gestaltRevisedTimeMgr = 2; { revised time mgr is present } æC æKY gestaltExtendedTimeMgr æFp GestaltEqu.p æT CONST æD gestaltExtendedTimeMgr = 3; { extended time mgr is present } æC æKY gestaltVMAttr æFp GestaltEqu.p æT CONST æD gestaltVMAttr = 'vm '; { virtual memory attributes } æC æKY gestaltVMPresent æFp GestaltEqu.p æT CONST æD gestaltVMPresent = 0; { true if virtual memory is present } æC æKY gestaltMachineType æFp GestaltEqu.p æT CONST æD { ************************ * Info-only selectors *********************** } gestaltMachineType = 'mach'; { machine type } æC æKY gestaltClassic æFp GestaltEqu.p æT CONST æD gestaltClassic = 1; æC æKY gestaltMacXL æFp GestaltEqu.p æT CONST æD gestaltMacXL = 2; æC æKY gestaltMac512KE æFp GestaltEqu.p æT CONST æD gestaltMac512KE = 3; æC æKY gestaltMacPlus æFp GestaltEqu.p æT CONST æD gestaltMacPlus = 4; æC æKY gestaltMacSE æFp GestaltEqu.p æT CONST æD gestaltMacSE = 5; æC æKY gestaltMacII æFp GestaltEqu.p æT CONST æD gestaltMacII = 6; æC æKY gestaltMacIIx æFp GestaltEqu.p æT CONST æD gestaltMacIIx = 7; æC æKY gestaltMacIIcx æFp GestaltEqu.p æT CONST æD gestaltMacIIcx = 8; æC æKY gestaltMacSE030 æFp GestaltEqu.p æT CONST æD gestaltMacSE030 = 9; æC æKY gestaltPortable æFp GestaltEqu.p æT CONST æD gestaltPortable = 10; æC æKY gestaltMacIIci æFp GestaltEqu.p æT CONST æD gestaltMacIIci = 11; æC æKY gestaltMacIIfx æFp GestaltEqu.p æT CONST æD gestaltMacIIfx = 13; æC æKY gestaltROMSize æFp GestaltEqu.p æT CONST æD gestaltROMSize = 'rom '; { rom size } æC æKY gestaltROMVersion æFp GestaltEqu.p æT CONST æD gestaltROMVersion = 'romv'; { rom version } æC æKY gestaltSystemVersion æFp GestaltEqu.p æT CONST æD gestaltSystemVersion = 'sysv'; { system version} æC æKY Gestalt æFp GestaltEqu.p æT FUNCTION æD FUNCTION Gestalt(selector: OSType;VAR response: LONGINT): OSErr; æDT myVariable := Gestalt(selector,response); æC Use the Gestalt function to obtain information about the operating environment. The information you need is indicated by the selector parameter, which Gestalt must already recognize. Trap macro _Gestalt On entry D0: selector code On exit A0: response D0: result code Upon successful completion of the function, the response parameter contains the information requested. Note that Gestalt returns the results from all function selectors in a long integer, occupying 4 bytes. In some cases, not all 4 bytes are needed to hold the returned information, in which case Gestalt places the information in the low-order bytes of the response parameter. Result codes noErr 0 No error gestaltUnknownErr –5550 Could not obtain the response gestaltUndefSelectorErr –5551 Undefined selector æKY NewGestalt æFp GestaltEqu.p æT FUNCTION æD FUNCTION NewGestalt(selector: OSType;gestaltFunction: ProcPtr): OSErr; æDT myVariable := NewGestalt(selector,gestaltFunction); æC Use the NewGestalt function to add selector codes to those already recognized by Gestalt. Trap macro _NewGestalt On entry A0: address of new selector function D0: selector code On exit D0: result code NewGestalt takes as parameters the selector to be registered and the function that Gestalt calls when it receives this selector. The interface for the selectorFunction function is defined in “Specifying Gestalt Selector Functions” earlier in this chapter. Result codes noErr 0 No error memFullErr –108 Ran out of memory gestaltDupSelectorErr –5552 Selector already exists gestaltLocationErr –5553 Function not in system heap æKY ReplaceGestalt æFp GestaltEqu.p æT FUNCTION æD FUNCTION ReplaceGestalt(selector: OSType;gestaltFunction: ProcPtr;VAR oldGestaltFunction: ProcPtr): OSErr; æDT myVariable := ReplaceGestalt(selector,gestaltFunction,oldGestaltFunction); æC The ReplaceGestalt function allows an application to replace the function that is currently associated with a selector. Trap macro _ReplaceGestalt On entry A0: address of new selector function D0: selector code On exit A0: address of old selector function D0: result code The interface for the selectorFunction function is defined in “Specifying Gestalt Selector Functions” earlier in this chapter. The new function must reside in the system heap and may want to call the function previously associated with the named selector. It may do so by using the address returned in the parameter oldGestaltFunction. If ReplaceGestalt returns an error of any type, then the value of oldGestaltFunction is undefined. Result codes noErr 0 No error gestaltUndefSelectorErr –5551 Undefined selector gestaltLocationErr –5553 Function not in system heap æKY Globals æKL ACount ANumber ApFontID ApplScratch AppParmHandle DABeeper DAStrings DefVCBPtr DlgFont DragPattern FCBSPtr FinderName FScaleDisable FSQHdr MBarEnable MBarHook MenuFlash MenuHook MenuList OldContent OldStructure PrintErr ROMFont0 SaveUpdate SaveVisRgn TheMenu ToExtFS ToolScratch VCBQHdr HiKeyLast KbdLast PCDeskPat Time ABusDCE ABusVars ADBBase AlarmState ApplLimit ApplZone ASCBase BootDrive BufPtr BufTgDate BufTgFBkNum BufTgFFlg BufTgFNum BusErrVct CaretTime ChunkyDepth ColLines CPUFlag CrsrAddr CrsrBase CrsrBusy CrsrCouple CrsrDevice CrsrNew CrsrObscure CrsrPin CrsrPtr CrsrRect CrsrRow CrsrSave CrsrScale CrsrState CrsrThresh CrsrVis CurActivate CurApName CurApRefNum CurDeactive CurDirStore CurJTOffset CurMap CurPageOption CurPitch CurrentA5 CurStackBase DefltStack DeskHook DeskPattern DeviceList DoubleTime DragHook DrvQHdr DSAlertRect DSAlertTab DSCtrAdj DSDrawProc DSErrCode DskErr DskVerify DSWndUpdate DTQFlags DTQueue DTskQHdr DTskQTail EjectNotify EndSRTPtr EventQueue EvtBufCnt ExpandMem ExtStsDT GetParam GhostWindow GrayRgn GZMoveHnd GZRootHnd GZRootPtr HeapEnd HiHeapMark HiliteMode HiliteRGB HpChk IAZNotify IconTLAddr IntFlag IntlSpec IWM JAllocCrsr JCrsrTask JDTInstall JFetch JGNEFilter JIODone JKybdTask JOpcodeProc JournalFlag JournalRef JSetCCrsr JStash JSwapMMU JVBLTask KbdType KbdVars Key1Trans Key2Trans KeyLast KeyMapLM KeyMVars KeypadMap KeyRepThresh KeyRepTime KeyThresh KeyTime LastTxGDevice LaunchFlag Lo3Bytes LoaderPBlock LoadTrap Lvl1DT Lvl2DT MainDevice MaskBC MaskHandle MaskPtr MBarHeight MBState MBTicks MemErr MemTop MickeyBytes MinStack MinusOne MMDefFlags MmInOK MMU32bit MMUFlags MMUFluff MMUTbl MMUTblSize MMUType MonkeyLives Mouse MouseMask MouseOffset MTemp NewCrsrJTbl NMIFlag OneOne PaintWhite PortAUse PortBUse PortList PWMBuf2 QDColors QDErrLM QDExist RAMBase RawMouse ResErr ResErrProc ResLoad ResReadOnly RestProc ResumeProc RGBBlack RGBWhite RndSeed ROM85 ROMBase ROMMapHndl RomMapInsert RowBits SaveSegHandle SCCASts SCCBSts SCCRd SCCWr ScrapCount ScrapEnd ScrapHandle ScrapInfo ScrapName ScrapSize ScrapState ScrapTag ScrapVars Scratch20 Scratch8 ScrDmpEnb ScrDmpType ScreenBytes ScreenRow ScrHRes ScrnBase ScrnVBLPtr ScrVRes SCSIBase SCSIDMA SCSIGlobals SCSIHsk SCSIPoll SdmBusErr SDMJmpTblPtr SdVolume SegHiEnable SerialVars SEVarBase SEvtEnb SFSaveDisk SInfoPtr SInitFlags SlotPrTbl SlotQDT SlotTICKS SlotVBLQ SoundActive SoundBase SoundDCE SoundLevel SoundPtr SoundVBL SPAlarm SPATalkA SPATalkB SPClikCaret SPConfig SPFont SPKbd SPMisc1 SPMisc2 SPPortA SPPortB SPPrint SPValid SPVolCtl SrcDevice SRsrcTblPtr StkLowPt SwitcherTPtr SysEvtBuf SysEvtMask SysMap SysMapHndl SysParam SysResName SysVersion SysZone TableSeed TagData TEDoText TERecal TEScrpHandle TEScrpLength TESysJust TEWdBreak TheCrsr TheGDevice TheZone Ticks TimeDBRA TimeLM TimeSCCDB TimeSCSIDB TmpResLoad TopMapHndl UnitNtryCnt UTableBase VBLQueue VertRRate VIA VIA2DT VideoInfoOK VidMode VidType WarmStart WindowList WMgrCPort WMgrPort WordRedraw WWExist æKY ACount æFp Globals æD ACount = $A9A [GLOBAL VAR] Stage number (0 through 3) of last alert (word) æKY ANumber æFp Globals æD ANumber = $A98 [GLOBAL VAR] Resource ID of last alert (word) æKY ApFontID æFp Globals æD ApFontID = $984 [GLOBAL VAR] Font number of application font (word) æKY ApplScratch æFp Globals æD ApplScratch = $A78 [GLOBAL VAR] 12-byte scratch area reserved for use by applications æKY AppParmHandle æFp Globals æD AppParmHandle = $AEC [GLOBAL VAR] Handle to Finder information æKY DABeeper æFp Globals æD DABeeper = $A9C [GLOBAL VAR] Address of current sound procedure æKY DAStrings æFp Globals æD DAStrings = $AA0 [GLOBAL VAR] Handles to ParamText strings (16 bytes) æKY DefVCBPtr æFp Globals æD DefVCBPtr = $352 [GLOBAL VAR] Pointer to default volume control block æKY DlgFont æFp Globals æD DlgFont = $AFA [GLOBAL VAR] Font number for dialogs and alerts (word) æKY DragPattern æFp Globals æD DragPattern = $A34 [GLOBAL VAR] Pattern of dragged region's outline (8 bytes) æKY FCBSPtr æFp Globals æD FCBSPtr = $34E [GLOBAL VAR] Pointer to file-control-block buffer æKY FinderName æFp Globals æD FinderName = $2E0 [GLOBAL VAR] Name of the Finder (length byte followed by up to 15 characters) æKY FScaleDisable æFp Globals æD FScaleDisable = $A63 [GLOBAL VAR] Nonzero to disable font scaling (byte) æKY FSQHdr æFp Globals æD FSQHdr = $360 [GLOBAL VAR] File I/O queue header (10 bytes) æKY MBarEnable æFp Globals æD MBarEnable = $A20 [GLOBAL VAR] Unique menu ID for active desk accessory, when menu bar belongs to the accessory (word) æKY MBarHook æFp Globals æD MBarHook = $A2C [GLOBAL VAR] Address of routine called by MenuSelect before menu is drawn æKY MenuFlash æFp Globals æD MenuFlash = $A24 [GLOBAL VAR] Count for duration of menu item blinking (word) æKY MenuHook æFp Globals æD MenuHook = $A30 [GLOBAL VAR] Address of routine called during MenuSelect æKY MenuList æFp Globals æD MenuList = $A1C [GLOBAL VAR] Handle to current menu list æKY OldContent æFp Globals æD OldContent = $9EA [GLOBAL VAR] Handle to saved content region æKY OldStructure æFp Globals æD OldStructure = $9E6 [GLOBAL VAR] Handle to saved structure region æKY PrintErr æFp Globals æD PrintErr = $944 [GLOBAL VAR] Result code from last Printing Manager routine (word) æKY ROMFont0 æFp Globals æD ROMFont0 = $980 [GLOBAL VAR] Handle to font record for system font æKY SaveUpdate æFp Globals æD SaveUpdate = $9DA [GLOBAL VAR] Flag for whether to generate update events (word) æKY SaveVisRgn æFp Globals æD SaveVisRgn = $9F2 [GLOBAL VAR] Handle to saved visRgn æKY TheMenu æFp Globals æD TheMenu = $A26 [GLOBAL VAR] Menu ID of currently highlighted menu (word) æKY ToExtFS æFp Globals æD ToExtFS = $3F2 [GLOBAL VAR] Pointer to external file system æKY ToolScratch æFp Globals æD ToolScratch = $9CE [GLOBAL VAR] 8-byte scratch area æKY VCBQHdr æFp Globals æD VCBQHdr = $356 [GLOBAL VAR] Volume-control-block queue header (10 bytes) æKY Graf3D.p æKL Clip3D GetPort3D Identity InitGrf3d Line2D Line3D LineTo2D LineTo3D LookAt Move2D Move3D MoveTo2D MoveTo3D Open3DPort Pitch Roll Scale SetPort3D SetPt2D SetPt3D Skew Transform Translate ViewAngle ViewPort Yaw Point2D Point3D Port3D Port3DHandle Port3DPtr radConst XfMatrix æKY radConst æFp Graf3D.p æT CONST æD radConst = 3754936; æC æKY Point3D æFp Graf3D.p æT RECORD æD Point3D = RECORD x: Fixed; y: Fixed; z: Fixed; END; æC æKY Point2D æFp Graf3D.p æT RECORD æD Point2D = RECORD x: Fixed; y: Fixed; END; æC æKY XfMatrix æFp Graf3D.p æT RECORD æD XfMatrix = ARRAY [0..3, 0..3] OF Fixed; æC æKY Port3D Port3DPtr Port3DHandle æFp Graf3D.p æT RECORD æD Port3DPtr = ^Port3D; Port3DHandle = ^Port3DPtr; Port3D = RECORD grPort: GrafPtr; viewRect: Rect; xLeft: Fixed; yTop: Fixed; xRight: Fixed; yBottom: Fixed; pen: Point3D; penPrime: Point3D; eye: Point3D; hSize: Fixed; vSize: Fixed; hCenter: Fixed; vCenter: Fixed; xCotan: Fixed; yCotan: Fixed; ident: BOOLEAN; xForm: XfMatrix; END; æC æKY InitGrf3d æFp Graf3D.p æT PROCEDURE æD PROCEDURE InitGrf3d(port: Port3DHandle); æDT InitGrf3d(port); æC æKY Open3DPort æFp Graf3D.p æT PROCEDURE æD PROCEDURE Open3DPort(port: Port3DPtr); æDT Open3DPort(port); æC æKY SetPort3D æFp Graf3D.p æT PROCEDURE æD PROCEDURE SetPort3D(port: Port3DPtr); æDT SetPort3D(port); æC SetPort sets the grafPort indicated by gp to be the current port. The global pointer thePort always points to the current port. All QuickDraw drawing routines affect the bitMap thePort^.portBits and use the local coordinate system of thePort^. Note that OpenPort and InitPort do a SetPort to the given port. Warning: Never do a SetPort to a port that has not been opened with OpenPort. Each port possesses its own pen and text characteristics which remain unchanged when the port is not selected as the current port. æKY GetPort3D æFp Graf3D.p æT PROCEDURE æD PROCEDURE GetPort3D(VAR port: Port3DPtr); æDT GetPort3D(port); æC GetPort returns a pointer to the current grafPort. If you have a program that draws into more than one grafPort, it's extremely useful to have each procedure save the current grafPort (with GetPort), set its own grafPort, do drawing or calculations, and then restore the previous grafPort (with SetPort). The pointer to the current grafPort is also available through the global pointer thePort, but you may prefer to use GetPort for better readability of your program text. For example, a procedure could do a GetPort (savePort) before setting its own grafPort and a SetPort (savePort) afterwards to restore the previous port. æKY MoveTo2D æFp Graf3D.p æT PROCEDURE æD PROCEDURE MoveTo2D(x: Fixed;y: Fixed); æDT MoveTo2D(x,y); æC MoveTo moves the pen to location (h,v) in the local coordinates of the current grafPort. No drawing is performed. æKY MoveTo3D æFp Graf3D.p æT PROCEDURE æD PROCEDURE MoveTo3D(x: Fixed;y: Fixed;z: Fixed); æDT MoveTo3D(x,y,z); æC æKY LineTo2D æFp Graf3D.p æT PROCEDURE æD PROCEDURE LineTo2D(x: Fixed;y: Fixed); æDT LineTo2D(x,y); æC This procedure draws a line to the location that is a distance of dh horizontally and dv vertically from the current pen location; it calls LineTo(h+dh,v+dv), where (h,v) is the current location. The positive directions are to the right and down. The pen location becomes the coordinates of the end of the line after the line is drawn. See the general discussion of drawing. If a region or polygon is open and being formed, its outline is infinitely thin and is not affected by the pnSize, pnMode, or pnPat. (See OpenRgn and OpenPoly.) æKY Move2D æFp Graf3D.p æT PROCEDURE æD PROCEDURE Move2D(dx: Fixed;dy: Fixed); æDT Move2D(dx,dy); æC æKY Move3D æFp Graf3D.p æT PROCEDURE æD PROCEDURE Move3D(dx: Fixed;dy: Fixed;dz: Fixed); æDT Move3D(dx,dy,dz); æC æKY Line2D æFp Graf3D.p æT PROCEDURE æD PROCEDURE Line2D(dx: Fixed;dy: Fixed); æDT Line2D(dx,dy); æC æKY Line3D æFp Graf3D.p æT PROCEDURE æD PROCEDURE Line3D(dx: Fixed;dy: Fixed;dz: Fixed); æDT Line3D(dx,dy,dz); æC æKY ViewPort æFp Graf3D.p æT PROCEDURE æD PROCEDURE ViewPort(r: Rect); æDT ViewPort(r); æC æKY LookAt æFp Graf3D.p æT PROCEDURE æD PROCEDURE LookAt(left: Fixed;top: Fixed;right: Fixed;bottom: Fixed); æDT LookAt(left,top,right,bottom); æC æKY ViewAngle æFp Graf3D.p æT PROCEDURE æD PROCEDURE ViewAngle(angle: Fixed); æDT ViewAngle(angle); æC æKY Identity æFp Graf3D.p æT PROCEDURE æD PROCEDURE Identity; æDT Identity(paramList); æC æKY Scale æFp Graf3D.p æT PROCEDURE æD PROCEDURE Scale(xFactor: Fixed;yFactor: Fixed;zFactor: Fixed); æDT Scale(xFactor,yFactor,zFactor); æC æKY Translate æFp Graf3D.p æT PROCEDURE æD PROCEDURE Translate(dx: Fixed;dy: Fixed;dz: Fixed); æDT Translate(dx,dy,dz); æC æKY Pitch æFp Graf3D.p æT PROCEDURE æD PROCEDURE Pitch(xAngle: Fixed); æDT Pitch(xAngle); æC æKY Yaw æFp Graf3D.p æT PROCEDURE æD PROCEDURE Yaw(yAngle: Fixed); æDT Yaw(yAngle); æC æKY Roll æFp Graf3D.p æT PROCEDURE æD PROCEDURE Roll(zAngle: Fixed); æDT Roll(zAngle); æC æKY Skew æFp Graf3D.p æT PROCEDURE æD PROCEDURE Skew(zAngle: Fixed); æDT Skew(zAngle); æC æKY Transform æFp Graf3D.p æT PROCEDURE æD PROCEDURE Transform(src: Point3D;VAR dst: Point3D); æDT Transform(src,dst); æC æKY Clip3D æFp Graf3D.p æT FUNCTION æD FUNCTION Clip3D(src1: Point3D;src2: Point3D;VAR dst1: Point;VAR dst2: Point): INTEGER; æDT myVariable := Clip3D(src1,src2,dst1,dst2); æC æKY SetPt3D æFp Graf3D.p æT PROCEDURE æD PROCEDURE SetPt3D(VAR pt3D: Point3D;x: Fixed;y: Fixed;z: Fixed); æDT SetPt3D(pt3D,x,y,z); æC SetPt assigns two integer coordinates to a variable of type Point. æKY SetPt2D æFp Graf3D.p æT PROCEDURE æD PROCEDURE SetPt2D(VAR pt2D: Point2D;x: Fixed;y: Fixed); æDT SetPt2D(pt2D,x,y); æC æKY LineTo3D æFp Graf3D.p æT PROCEDURE æD PROCEDURE LineTo3D(x: Fixed;y: Fixed;z: Fixed); æDT LineTo3D(x,y,z); æC æKY HyperXCmd.p æKL BoolToStr EvalExpr ExtToStr GetFieldByID GetFieldByName GetFieldByNum GetGlobal LongToStr NumToHex NumToStr PasToZero ReturnToPas ScanToReturn ScanToZero SendCardMessage SendHCMessage SetFieldByID SetFieldByName SetFieldByNum SetGlobal StringEqual StringLength StringMatch StrToBool StrToExt StrToLong StrToNum ZeroBytes ZeroToPas XCmdBlock XCmdPtr xreqBoolToStr xreqEvalExpr xreqExtToStr xreqGetFieldByID xreqGetFieldByName xreqGetFieldByNum xreqGetGlobal xreqLongToStr xreqNumToHex xreqNumToStr xreqPasToZero xreqReturnToPas xreqScanToReturn xreqScanToZero xreqSendCardMessage xreqSendHCMessage xreqSetFieldByID xreqSetFieldByName xreqSetFieldByNum xreqSetGlobal xreqStringEqual xreqStringLength xreqStringMatch xreqStrToBool xreqStrToExt xreqStrToLong xreqStrToNum xreqZeroBytes xreqZeroToPas xresFail xresNotImp xresSucc æKY xresSucc æFp HyperXCmd.p æT CONST æD { result codes } xresSucc = 0; æC æKY xresFail æFp HyperXCmd.p æT CONST æD xresFail = 1; æC æKY xresNotImp æFp HyperXCmd.p æT CONST æD xresNotImp = 2; æC æKY xreqSendCardMessage æFp HyperXCmd.p æT CONST æD { request codes } xreqSendCardMessage = 1; æC æKY xreqEvalExpr æFp HyperXCmd.p æT CONST æD xreqEvalExpr = 2; æC æKY xreqStringLength æFp HyperXCmd.p æT CONST æD xreqStringLength = 3; æC æKY xreqStringMatch æFp HyperXCmd.p æT CONST æD xreqStringMatch = 4; æC æKY xreqSendHCMessage æFp HyperXCmd.p æT CONST æD xreqSendHCMessage = 5; æC æKY xreqZeroBytes æFp HyperXCmd.p æT CONST æD xreqZeroBytes = 6; æC æKY xreqPasToZero æFp HyperXCmd.p æT CONST æD xreqPasToZero = 7; æC æKY xreqZeroToPas æFp HyperXCmd.p æT CONST æD xreqZeroToPas = 8; æC æKY xreqStrToLong æFp HyperXCmd.p æT CONST æD xreqStrToLong = 9; æC æKY xreqStrToNum æFp HyperXCmd.p æT CONST æD xreqStrToNum = 10; æC æKY xreqStrToBool æFp HyperXCmd.p æT CONST æD xreqStrToBool = 11; æC æKY xreqStrToExt æFp HyperXCmd.p æT CONST æD xreqStrToExt = 12; æC æKY xreqLongToStr æFp HyperXCmd.p æT CONST æD xreqLongToStr = 13; æC æKY xreqNumToStr æFp HyperXCmd.p æT CONST æD xreqNumToStr = 14; æC æKY xreqNumToHex æFp HyperXCmd.p æT CONST æD xreqNumToHex = 15; æC æKY xreqBoolToStr æFp HyperXCmd.p æT CONST æD xreqBoolToStr = 16; æC æKY xreqExtToStr æFp HyperXCmd.p æT CONST æD xreqExtToStr = 17; æC æKY xreqGetGlobal æFp HyperXCmd.p æT CONST æD xreqGetGlobal = 18; æC æKY xreqSetGlobal æFp HyperXCmd.p æT CONST æD xreqSetGlobal = 19; æC æKY xreqGetFieldByName æFp HyperXCmd.p æT CONST æD xreqGetFieldByName = 20; æC æKY xreqGetFieldByNum æFp HyperXCmd.p æT CONST æD xreqGetFieldByNum = 21; æC æKY xreqGetFieldByID æFp HyperXCmd.p æT CONST æD xreqGetFieldByID = 22; æC æKY xreqSetFieldByName æFp HyperXCmd.p æT CONST æD xreqSetFieldByName = 23; æC æKY xreqSetFieldByNum æFp HyperXCmd.p æT CONST æD xreqSetFieldByNum = 24; æC æKY xreqSetFieldByID æFp HyperXCmd.p æT CONST æD xreqSetFieldByID = 25; æC æKY xreqStringEqual æFp HyperXCmd.p æT CONST æD xreqStringEqual = 26; æC æKY xreqReturnToPas æFp HyperXCmd.p æT CONST æD xreqReturnToPas = 27; æC æKY xreqScanToReturn æFp HyperXCmd.p æT CONST æD xreqScanToReturn = 28; æC æKY xreqScanToZero æFp HyperXCmd.p æT CONST æD xreqScanToZero = 39; { Yes, really 39!} æC æKY XCmdBlock XCmdPtr æFp HyperXCmd.p æT RECORD æD XCmdPtr = ^XCmdBlock; XCmdBlock = RECORD paramCount: INTEGER; params: ARRAY [1..16] OF Handle; returnValue: Handle; passFlag: BOOLEAN; entryPoint: ProcPtr; {to call back to HyperCard} request: INTEGER; result: INTEGER; inArgs: ARRAY [1..8] OF LONGINT; outArgs: ARRAY [1..4] OF LONGINT; END; æC æKY SendCardMessage æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE SendCardMessage(paramPtr: XCmdPtr;msg: Str255); { Message sending } æDT SendCardMessage(paramPtr,msg); æC æKY SendHCMessage æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE SendHCMessage(paramPtr: XCmdPtr;msg: Str255); æDT SendHCMessage(paramPtr,msg); æC æKY GetGlobal æFp HyperXCmd.p æT FUNCTION æD FUNCTION GetGlobal(paramPtr: XCmdPtr;globName: Str255): Handle; { Container access } æDT myVariable := GetGlobal(paramPtr,globName); æC æKY SetGlobal æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE SetGlobal(paramPtr: XCmdPtr;globName: Str255;globValue: Handle); æDT SetGlobal(paramPtr,globName,globValue); æC æKY GetFieldByID æFp HyperXCmd.p æT FUNCTION æD FUNCTION GetFieldByID(paramPtr: XCmdPtr;cardFieldFlag: BOOLEAN;fieldID: INTEGER): Handle; æDT myVariable := GetFieldByID(paramPtr,cardFieldFlag,fieldID); æC æKY GetFieldByName æFp HyperXCmd.p æT FUNCTION æD FUNCTION GetFieldByName(paramPtr: XCmdPtr;cardFieldFlag: BOOLEAN;fieldName: Str255): Handle; æDT myVariable := GetFieldByName(paramPtr,cardFieldFlag,fieldName); æC æKY GetFieldByNum æFp HyperXCmd.p æT FUNCTION æD FUNCTION GetFieldByNum(paramPtr: XCmdPtr;cardFieldFlag: BOOLEAN;fieldNum: INTEGER): Handle; æDT myVariable := GetFieldByNum(paramPtr,cardFieldFlag,fieldNum); æC æKY SetFieldByID æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE SetFieldByID(paramPtr: XCmdPtr;cardFieldFlag: BOOLEAN;fieldID: INTEGER; fieldVal: Handle); æDT SetFieldByID(paramPtr,cardFieldFlag,fieldID,fieldVal); æC æKY SetFieldByName æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE SetFieldByName(paramPtr: XCmdPtr;cardFieldFlag: BOOLEAN;fieldName: Str255; fieldVal: Handle); æDT SetFieldByName(paramPtr,cardFieldFlag,fieldName,fieldVal); æC æKY SetFieldByNum æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE SetFieldByNum(paramPtr: XCmdPtr;cardFieldFlag: BOOLEAN;fieldNum: INTEGER; fieldVal: Handle); æDT SetFieldByNum(paramPtr,cardFieldFlag,fieldNum,fieldVal); æC æKY BoolToStr æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE BoolToStr(paramPtr: XCmdPtr;bool: BOOLEAN;VAR str: Str255); { String conversion } æDT BoolToStr(paramPtr,bool,str); æC æKY ExtToStr æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE ExtToStr(paramPtr: XCmdPtr;num: extended;VAR str: Str255); æDT ExtToStr(paramPtr,num,str); æC æKY LongToStr æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE LongToStr(paramPtr: XCmdPtr;posNum: LONGINT;VAR str: Str255); æDT LongToStr(paramPtr,posNum,str); æC æKY NumToStr æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE NumToStr(paramPtr: XCmdPtr;num: LONGINT;VAR str: Str255); æDT NumToStr(paramPtr,num,str); æC æKY NumToHex æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE NumToHex(paramPtr: XCmdPtr;num: LONGINT;nDigits: INTEGER;VAR str: Str255); æDT NumToHex(paramPtr,num,nDigits,str); æC æKY StrToBool æFp HyperXCmd.p æT FUNCTION æD FUNCTION StrToBool(paramPtr: XCmdPtr;str: Str255): BOOLEAN; æDT myVariable := StrToBool(paramPtr,str); æC æKY StrToExt æFp HyperXCmd.p æT FUNCTION æD FUNCTION StrToExt(paramPtr: XCmdPtr;str: Str255): extended; æDT myVariable := StrToExt(paramPtr,str); æC æKY StrToLong æFp HyperXCmd.p æT FUNCTION æD FUNCTION StrToLong(paramPtr: XCmdPtr;str: Str255): LONGINT; æDT myVariable := StrToLong(paramPtr,str); æC æKY StrToNum æFp HyperXCmd.p æT FUNCTION æD FUNCTION StrToNum(paramPtr: XCmdPtr;str: Str255): LONGINT; æDT myVariable := StrToNum(paramPtr,str); æC æKY PasToZero æFp HyperXCmd.p æT FUNCTION æD FUNCTION PasToZero(paramPtr: XCmdPtr;str: Str255): Handle; æDT myVariable := PasToZero(paramPtr,str); æC æKY ZeroToPas æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE ZeroToPas(paramPtr: XCmdPtr;zeroStr: Ptr;VAR pasStr: Str255); æDT ZeroToPas(paramPtr,zeroStr,pasStr); æC æKY EvalExpr æFp HyperXCmd.p æT FUNCTION æD FUNCTION EvalExpr(paramPtr: XCmdPtr;expr: Str255): Handle; { Miscellaneous } æDT myVariable := EvalExpr(paramPtr,expr); æC æKY ReturnToPas æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE ReturnToPas(paramPtr: XCmdPtr;zeroStr: Ptr;VAR pasStr: Str255); æDT ReturnToPas(paramPtr,zeroStr,pasStr); æC æKY ScanToReturn æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE ScanToReturn(paramPtr: XCmdPtr;VAR scanPtr: Ptr); æDT ScanToReturn(paramPtr,scanPtr); æC æKY ScanToZero æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE ScanToZero(paramPtr: XCmdPtr;VAR scanPtr: Ptr); æDT ScanToZero(paramPtr,scanPtr); æC æKY StringEqual æFp HyperXCmd.p æT FUNCTION æD FUNCTION StringEqual(paramPtr: XCmdPtr;str1: Str255;str2: Str255): BOOLEAN; æDT myVariable := StringEqual(paramPtr,str1,str2); æC æKY StringMatch æFp HyperXCmd.p æT FUNCTION æD FUNCTION StringMatch(paramPtr: XCmdPtr;pattern: Str255;target: Ptr): Ptr; æDT myVariable := StringMatch(paramPtr,pattern,target); æC æKY StringLength æFp HyperXCmd.p æT FUNCTION æD FUNCTION StringLength(paramPtr: XCmdPtr;strPtr: Ptr): LONGINT; æDT myVariable := StringLength(paramPtr,strPtr); æC æKY ZeroBytes æFp HyperXCmd.p æT PROCEDURE æD PROCEDURE ZeroBytes(paramPtr: XCmdPtr;dstPtr: Ptr;longCount: LONGINT); æDT ZeroBytes(paramPtr,dstPtr,longCount); æC æKY Lists.p æKL LActivate LAddColumn LAddRow LAddToCell LAutoScroll LCellSize LClick LClrCell LDelColumn LDelRow LDispose LDoDraw LDraw LFind LGetCell LGetSelect LLastClick LNew LNextCell LRect LScroll LSearch LSetCell LSetSelect LSize LUpdate Cell DataArray DataHandle DataPtr lCloseMsg lDoHAutoscroll lDoVAutoscroll lDrawMsg lExtendDrag lHiliteMsg lInitMsg ListHandle ListPtr ListRec lNoDisjoint lNoExtend lNoNilHilite lNoRect lOnlyOne lUseSense æKY lDoVAutoscroll æFp Lists.p æT CONST æD lDoVAutoscroll = 2; æC æKY lDoHAutoscroll æFp Lists.p æT CONST æD lDoHAutoscroll = 1; æC æKY lOnlyOne æFp Lists.p æT CONST æD lOnlyOne = -128; æC æKY lExtendDrag æFp Lists.p æT CONST æD lExtendDrag = 64; æC æKY lNoDisjoint æFp Lists.p æT CONST æD lNoDisjoint = 32; æC æKY lNoExtend æFp Lists.p æT CONST æD lNoExtend = 16; æC æKY lNoRect æFp Lists.p æT CONST æD lNoRect = 8; æC æKY lUseSense æFp Lists.p æT CONST æD lUseSense = 4; æC æKY lNoNilHilite æFp Lists.p æT CONST æD lNoNilHilite = 2; æC æKY lInitMsg æFp Lists.p æT CONST æD lInitMsg = 0; æC æKY lDrawMsg æFp Lists.p æT CONST æD lDrawMsg = 1; æC æKY lHiliteMsg æFp Lists.p æT CONST æD lHiliteMsg = 2; æC æKY lCloseMsg æFp Lists.p æT CONST æD lCloseMsg = 3; æC æKY Cell æFp Lists.p æT RECORD æD Cell = Point; æC æKY ListRec ListPtr ListHandle æFp Lists.p æT RECORD æD ListPtr = ^ListRec; ListHandle = ^ListPtr; ListRec = RECORD rView: Rect; port: GrafPtr; indent: Point; cellSize: Point; visible: Rect; vScroll: ControlHandle; hScroll: ControlHandle; selFlags: SignedByte; lActive: BOOLEAN; lReserved: SignedByte; listFlags: SignedByte; clikTime: LONGINT; clikLoc: Point; mouseLoc: Point; lClikLoop: ProcPtr; lastClick: Cell; refCon: LONGINT; listDefProc: Handle; userHandle: Handle; dataBounds: Rect; cells: DataHandle; maxIndex: INTEGER; cellArray: PACKED ARRAY [1..1] OF INTEGER; END; æC »The List Record Data Structure The exact data structure of a list record is as follows: TYPE Cell = Point; DataArray = PACKED ARRAY [0..32000] OF CHAR; DataPtr = ^DataArray; DataHandle = ^DataPtr; ListRec = RECORD rView: Rect; {list's display rectangle} port: GrafPtr; {list's grafPort} indent: Point; {indent distance} cellSize: Point; {cell size} visible: Rect; {boundary of visible cells} vScroll: ControlHandle; {vertical scroll bar} hScroll: ControlHandle; {horizontal scroll bar} selFlags: SignedByte; {selection flags} lActive: BOOLEAN; {TRUE if active} lReserved: SignedByte; {reserved} listFlags: SignedByte; {automatic scrolling flags} clikTime: LONGINT; {time of last click} clikLoc: Point; {position of last click} mouseLoc: Point; {current mouse location} lClikLoop: Ptr; {routine for LClick} lastClick: Cell; {last cell clicked} refCon: LONGINT; {list's reference value} listDefProc: Handle; {list definition procedure} userHandle: Handle; {additional storage} dataBounds: Rect; {boundary of cells allocated} cells: DataHandle; {cell data} maxIndex: INTEGER; {used internally} cellArray: ARRAY [1..1] OF INTEGER {offsets to data} END; ListPtr = ^ListRec; ListHandle = ^ListPtr; RView is the rectangle, given in the local coordinates of the grafPort, in which the list is displayed. Room for scroll bars is not included in this rectangle. If the list has scroll bars and is to fill the entire window, rView should be 15 points smaller in each dimension than the grafPort. Port is the grafPort used by the list; it’s set to the port of the window specified when the list is created. Indent is the distance in pixels that the list definition procedure should indent from the topLeft of the cell when drawing the contents. The default value for indent is 0, but it can be set by the list definition procedure. CellSize is the size of a cell in pixels. If it’s not specified when the list is created, a default cell size is set. CellSize.v is set to the ascent plus descent plus leading of the port’s font, and cellSize.h is set to (rView.right – rView.left) DIV (dataBounds.right – dataBounds.left) A cell is a box in which a list element is displayed. Cells are identified by their column and row numbers. In Figure 1, for instance, the highlighted cell is in column 1, row 2. Cells are declared as points, using the Point data type simply as a way of specifying the column and row number of a cell. Similarly, visible and dataBounds use the Rect data type to specify a rectangular set of cells as two diagonally opposite cell coordinates (rather than two diagonally opposite points in the local coordinates of a grafPort). DataBounds is the boundary of the cells currently allocated, specified by row and column. The list in Figure 1 (assuming the entire list is visible) has seventeen rows and five columns of cells. DataBounds for this list can be represented, using the QuickDraw rectangle notation (left,top)(right,bottom), as (0,0)(5,17). Notice that the column and row specified for the bottom right of dataBounds are 1 greater in each dimension than the column and row number of the bottom right cell. Thus, you can test to see if a cell is a valid cell within the boundary of a list using the statement: IF PtInRect(c,myList^^.dataBounds) THEN... The visible rectangle reflects which cells are currently within the visible part of the list; it’s calculated by the List Manager according to the values you specify for rView, dataBounds, and cellSize when you create the list. (Visible.topLeft is the row and column of the top left visible cell; visible.botRight is 1 greater in both dimensions than the row and column of the bottom right visible cell.) For example, if only four cells—row 2, column 0; row 2, column 1; row 3, column 0; and row 3, column 1—are visible, the visible rectangle is (0,2)(2,4). You can test to see if a cell is visible using the statement: IF PtInRect(c,myList^^.visible) THEN... •••Refer to Figure 1.••• Figure 1–A Sample List SelFlags contains selection flags for the List Manager. It’s initialized to 0; with this setting, the List Manager selects cells according to the Macintosh User Interface Guidelines. The meaning of these flags is explained below in the section “Cell Selection Algorithm”. The listFlags field contains automatic scrolling flags; the List Manager sets these flags automatically when you specify scroll bars. There are predefined constants that let you set or test the status of the corresponding bits: CONST lDoVAutoScroll = 2; {set to allow automatic vertical scrolling} lDoHAutoScroll = 1; {set to allow automatic horizontal scrolling} ClikLoc is the position of the last mouse click in local coordinates; you can use it in the list definition procedure to get the position within the cell. LClikLoop is a pointer to the routine to be called during the LClick function, as described later. LastClick contains the cell coordinates of the last cell clicked in. RefCon is the list’s reference value field, which the application may store into and access for any purpose. In addition, the application may use the field userHandle to store a handle to an additional storage area. CellArray contains offsets to the cell data. For each list element, this includes the bit indicating whether the cell is selected or not. »The LClikLoop Field The lClikLoop field of a list record lets you specify a routine that will be called repeatedly (by the LClick function, described below) as long as the mouse button is held down within the rView rectangle or its scroll bars. Note: The LClick function performs automatic scrolling if the mouse is dragged outside the visible rectangle, so there’s no need to write a list click loop routine to do automatic scrolling. The list click loop routine has no parameters and returns a Boolean value. You could declare a list click loop routine named MyClikLoop like this: FUNCTION MyClikLoop : BOOLEAN; The function should return TRUE. You must put a pointer to your list click loop routine in the lClikLoop field of the list record so that the List Manager will call your routine. Warning: Returning FALSE from your list click loop routine tells the LClick function that the mouse button has been released, which aborts LClick. Assembly-language note: Your routine should set register D0 to 1; returning 0 in register D0 aborts LClick. For your convenience, register D5 contains the current mouse location. æKY DataArray DataPtr DataHandle æFp Lists.p æT RECORD æD DataPtr = ^DataArray; DataHandle = ^DataPtr; DataArray = PACKED ARRAY [0..32000] OF CHAR; æC æKY LNew æFp Lists.p æT FUNCTION æTN $A9E7 æD FUNCTION LNew(rView: Rect;dataBounds: Rect;cSize: Point;theProc: INTEGER; theWindow: WindowPtr;drawIt: BOOLEAN;hasGrow: BOOLEAN;scrollHoriz: BOOLEAN; scrollVert: BOOLEAN): ListHandle; INLINE $3F3C,$0044,$A9E7; æDT myVariable := LNew(rView,dataBounds,cSize,theProc,theWindow,drawIt,hasGrow,scrollHoriz,scrollVert); æRI IV-270 æC Call LNew to create a new list. It returns a handle to the new list. The list’s grafPort is set to theWindow’s port. If drawIt is FALSE, the list is not displayed. RView specifies, in the local coordinates of theWindow, the rectangle in which the list will be displayed. (Remember that this doesn’t include space for scroll bars. If the list, including scroll bars, is to fill the entire window, rView should be 15 points smaller in each dimension than theWindow’s portRect.) DataBounds is the rectangle for specifying the initial array dimensions of the list. For example to preallocate space for a list that’s 5 cells across by 10 cells down, you should set dataBounds to (0,0)(5,10). If you want to allocate the space for a one-column list, set dataBounds to (0,0)(1,0) and use LAddRow. CSize.h and cSize.v are the desired height and width of each cell in pixels; if they’re not specified, a default cell size is calculated (as described above). TheProc is the resource ID of your list definition procedure; for a text-only list, pass 0 and the default list definition procedure (about 150 bytes in size) will be used. The list definition procedure is called to initialize itself after all other list record fields have been initialized; thus, it can use any of the values in the list record (or set particular fields, such as the indent distance). If hasGrow is TRUE, the scroll bars are sized so that there’s room for a size box in the standard position. It’s up to the program to display the size box (using the Window Manager procedure DrawGrowIcon). If scrollHoriz is TRUE, a horizontal scroll bar is placed immediately below rView and all horizontal scrolling functions are implemented. If scrollVert is TRUE, a vertical scroll bar is placed immediately to the right of rView and all vertical scrolling functions are implemented. The visible rectangle is set to contain as many cells of cSize (or the default) as will fit into rView. If the cells do not fit exactly into rView, the visible rectangle is rounded up to the nearest cell. Scrolling will always allow all cells to be fully displayed. The selection flags are set to 0, and the active flag is set to TRUE. Note: Scrolling looks best if rView is a multiple of cSize.v in height. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LDispose æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LDispose(lHandle: ListHandle); INLINE $3F3C,$0028,$A9E7; æDT LDispose(lHandle); æRI IV-271 æC Call LDispose when you are through using a list. It issues a close call to the list definition procedure, and calls the Memory Manager procedure DisposHandle for the data handle, the Control Manager procedure DisposeControl for both scroll bars (if they’re there), and DisposHandle for the list record. Note: Calling LDispose is much faster than deleting one row at a time. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LAddColumn æFp Lists.p æT FUNCTION æTN $A9E7 æD FUNCTION LAddColumn(count: INTEGER;colNum: INTEGER;lHandle: ListHandle): INTEGER; INLINE $3F3C,$0004,$A9E7; æDT myVariable := LAddColumn(count,colNum,lHandle); æRI IV-271 æC LAddColumn inserts into the given list the number of columns specified by the count parameter, starting at the column specified by colNum. Column numbers that are greater than or equal to colNum are increased by count. If colNum is not within dataBounds, new last columns are added. The number of the first added column is returned and dataBounds.right is increased by count. All cells added are empty. If there are no cells (because dataBounds.top = dataBounds.bottom), no cells are added, but dataBounds is still extended. If drawing is on and the added columns (which are empty) are visible, the list and its scroll bars are updated. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LAddRow æFp Lists.p æT FUNCTION æTN $A9E7 æD FUNCTION LAddRow(count: INTEGER;rowNum: INTEGER;lHandle: ListHandle): INTEGER; INLINE $3F3C,$0008,$A9E7; æDT myVariable := LAddRow(count,rowNum,lHandle); æRI IV-271 æC LAddRow inserts the number of rows specified by the count parameter, starting at the row specified by rowNum. Row numbers that are greater than or equal to rowNum are increased by count. If rowNum is not within dataBounds, new last rows are added. The number of the first added row is returned, and dataBounds.bottom is increased by count. All cells added are empty. If there are no cells (because dataBounds.left = dataBounds.right), no cells are added, but dataBounds is still extended. If drawing is on and the added rows (which are empty) are visible, the list and its scroll bars are updated. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LDelColumn æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LDelColumn(count: INTEGER;colNum: INTEGER;lHandle: ListHandle); INLINE $3F3C,$0020,$A9E7; æDT LDelColumn(count,colNum,lHandle); æRI IV-271 æC LDelColumn deletes the number of columns specified by the count parameter, starting with the column specified by colNum. Column numbers that are greater than colNum are decreased by count. If colNum is not within dataBounds, nothing is done. DataBounds.right is decreased by count. If drawing is on and the deleted columns were visible, the list and its scroll bars are updated. If count is 0, or colNum = dataBounds.left AND count > = dataBounds.right – dataBounds.left all the data in the list is quickly deleted, dataBounds.right is set to dataBounds.left, and the number of rows is left unchanged. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LDelRow æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LDelRow(count: INTEGER;rowNum: INTEGER;lHandle: ListHandle); INLINE $3F3C,$0024,$A9E7; æDT LDelRow(count,rowNum,lHandle); æRI IV-272 æC LDelRow deletes the number of rows specified by the count parameter, starting with the row specified by rowNum. Row numbers that are greater than rowNum are decreased by count. If rowNum is not within dataBounds, nothing is done. DataBounds.bottom is decreased by count. If drawing is on and the deleted rows were visible, the list and its scroll bars are updated. If count is 0, or rowNum = dataBounds.top AND count > = dataBounds.bottom – dataBounds.top all the data in the list is quickly deleted, dataBounds.bottom is set to dataBounds.top, and the number of columns is left unchanged. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LGetSelect æFp Lists.p æT FUNCTION æTN $A9E7 æD FUNCTION LGetSelect(next: BOOLEAN;VAR theCell: Cell;lHandle: ListHandle): BOOLEAN; INLINE $3F3C,$003C,$A9E7; æDT myVariable := LGetSelect(next,theCell,lHandle); æRI IV-273 æC If next is FALSE, LGetSelect returns TRUE if the specified cell is selected, or FALSE if not. If next is TRUE, LGetSelect returns in c the cell coordinates of the next selected cell in the row that is greater than or equal to theCell. If there are no more cells in the row, it returns in theCell the cell coordinates of the next selected cell in the next row. If there are no more rows, FALSE is returned. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LLastClick æFp Lists.p æT FUNCTION æTN $A9E7 æD FUNCTION LLastClick(lHandle: ListHandle): Cell; INLINE $3F3C,$0040,$A9E7; æDT myVariable := LLastClick(lHandle); æRI IV-273 æC LLastClick returns the cell coordinates of the last cell clicked in. If no cell has been clicked in since LNew, the value returned (for both integers) is negative. Note: The value returned by this call is not the last cell double-clicked in, or the last cell selected, but merely the last cell clicked in. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LNextCell æFp Lists.p æT FUNCTION æTN $A9E7 æD FUNCTION LNextCell(hNext: BOOLEAN;vNext: BOOLEAN;VAR theCell: Cell;lHandle: ListHandle): BOOLEAN; INLINE $3F3C,$0048,$A9E7; æDT myVariable := LNextCell(hNext,vNext,theCell,lHandle); æRI IV-274 æC Given a cell in theCell, LNextCell returns in theCell the next cell in the list. If both hNext and vNext are TRUE, theCell is first advanced to the next cell in the row. If there are no more cells in the row, theCell is set to the first cell in the next row. If there are no more rows, FALSE is returned. If only hNext is TRUE, theCell is advanced within the current row. If only vNext is TRUE, theCell is advanced within the current column. FALSE is returned if there are no remaining cells in the row or column. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LSearch æFp Lists.p æT FUNCTION æTN $A9E7 æD FUNCTION LSearch(dataPtr: Ptr;dataLen: INTEGER;searchProc: ProcPtr;VAR theCell: Cell; lHandle: ListHandle): BOOLEAN; INLINE $3F3C,$0054,$A9E7; æDT myVariable := LSearch(dataPtr,dataLen,searchProc,theCell,lHandle); æRI IV-274 æC LSearch searches for the first cell greater than or equal to theCell that contains the specified data. If a cell containing matching data is found, the function result TRUE is returned, and the cell coordinates are returned in theCell. If searchProc is NIL, the International Utilities Package function IUMagIDString is called to compare the specified data with the contents of each cell. If searchProc is not NIL, the routine pointed to by searchProc is called. Note: Your searchProc should have the same parameters as the IUMagIDString function. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LSize æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LSize(listWidth: INTEGER;listHeight: INTEGER;lHandle: ListHandle); INLINE $3F3C,$0060,$A9E7; æDT LSize(listWidth,listHeight,lHandle); æRI IV-274 æC You’ll usually call LSize immediately after the Window Manager procedure SizeWindow. It causes the bottom right of the list to be adjusted so that the list is the width and height indicated by listWidth and listHeight. The contents of the list and the scroll bars are adjusted and redrawn as necessary. The values of listWidth and listHeight do not include the scroll bars; for a list that entirely fills the window, listWidth and listHeight should be 15 fewer pixels than the portRect if both scroll bars are present. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LDoDraw æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LDoDraw(drawIt: BOOLEAN;lHandle: ListHandle); INLINE $3F3C,$002C,$A9E7; æDT LDoDraw(drawIt,lHandle); æRI IV-275 æC LDoDraw sets the List Manager’s drawing mode to the state specified by drawIt. If drawIt is TRUE, changes made by most List Manager calls will cause some sort of drawing to take place. If drawIt is FALSE, all cell drawing is disabled. (Two exceptions: The scroll bars are still updated after LSize, and the scroll arrows are still highlighted if the user clicks them.) The recommended use of LDoDraw is to disable drawing while you’re building a list (that is, adding rows or columns, setting or changing cell values, or setting default selections). Once you’ve finished building the list, you should then re-enable drawing. In general, drawing should be on while you’re in your event loop and dispatching events to the List Manager. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LScroll æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LScroll(dCols: INTEGER;dRows: INTEGER;lHandle: ListHandle); INLINE $3F3C,$0050,$A9E7; æDT LScroll(dCols,dRows,lHandle); æRI IV-275 æC LScroll scrolls the given list by the number of columns and rows specified in dCols and dRows, either positively (down and to the right) or negatively (up and to the left). Scrolling is pinned to the list’s dataBounds. If drawing is on, LScroll does all necessary updating of the screen. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LAutoScroll æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LAutoScroll(lHandle: ListHandle); INLINE $3F3C,$0010,$A9E7; æDT LAutoScroll(lHandle); æRI IV-275 æC For the given list, LAutoScroll scrolls the list until the first selected cell is visible. It automatically places the first selected cell in the top left corner of the visible rectangle. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LUpdate æFp Lists.p æT PROCEDURE æTN ,$A9E7 æD PROCEDURE LUpdate(theRgn: RgnHandle;lHandle: ListHandle); INLINE $3F3C,$0064,$A9E7; æDT LUpdate(theRgn,lHandle); æRI IV-275 æC LUpdate should be called in response to an update event. TheRgn should be set to the visRgn of the list’s port (for more details, see the BeginUpdate procedure in the Window Manager chapter). It redraws any visible cells in lHandle that intersect theRgn. It also redraws the controls, if necessary. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LActivate æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LActivate(act: BOOLEAN;lHandle: ListHandle); INLINE $3F3C,$0000,$A9E7; æDT LActivate(act,lHandle); æRI IV-276 æC Call LActivate to activate or deactivate the list specified by lHandle (in response to an activate event in the window containing the list). The act parameter should be set to TRUE to activate the list, or FALSE to deactivate the list. LActivate highlights or unhighlights the selections, and shows or hides the scroll bars (but not the size box, if any). Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LCellSize æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LCellSize(cSize: Point;lHandle: ListHandle); INLINE $3F3C,$0014,$A9E7; æDT LCellSize(cSize,lHandle); æRI IV-273 æC LCellSize sets the cellSize field in the list record to cSize and updates the visible rectangle to contain cells of this size. This command should be used only before any cells have been drawn. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LClick æFp Lists.p æT FUNCTION æTN $A9E7 æD FUNCTION LClick(pt: Point;modifiers: INTEGER;lHandle: ListHandle): BOOLEAN; INLINE $3F3C,$0018,$A9E7; æDT myVariable := LClick(pt,modifiers,lHandle); æRI IV-273 æC Call LClick when there is a mouse-down event in the destination rectangle or its scroll bars. Pt is the mouse location in local coordinates. Modifiers is the modifiers word from the event record. LHandle is the list to be tracked. The result is TRUE if a double-click occurred (and the two clicks took place within the same cell). LClick keeps control until the mouse is released; each time through its inner loop, it calls the routine whose pointer is in the lClikLoop field of the list record. If the mouse is in the visible rectangle, cells are selected according to the state of the modifiers and the selection flags. If the mouse was in the cells but is dragged outside the list’s rectangle, the list is auto-scrolled. If the mouse was in a control, the control’s definition procedure is called to track the mouse. To discover which cell was clicked in, use the LLastClick function. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LAddToCell æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LAddToCell(dataPtr: Ptr;dataLen: INTEGER;theCell: Cell;lHandle: ListHandle); INLINE $3F3C,$000C,$A9E7; æDT LAddToCell(dataPtr,dataLen,theCell,lHandle); æRI IV-272 æC LAddToCell appends the data pointed to by dataPtr and of length dataLen to the cell specified by theCell in lHandle. If drawing is off, you must turn drawing on and call LDraw (or LUpdate) to display the cell’s new value. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LClrCell æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LClrCell(theCell: Cell;lHandle: ListHandle); INLINE $3F3C,$001C,$A9E7; æDT LClrCell(theCell,lHandle); æRI IV-272 æC LClrCell clears the contents of the specified cell (by setting the length to 0). If theCell is not a valid cell, nothing is done. If drawing is off, you must turn drawing on and call LDraw to display the cell’s new value (or simply call the Window Manager procedure InvalRect). Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LGetCell æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LGetCell(dataPtr: Ptr;VAR dataLen: INTEGER;theCell: Cell;lHandle: ListHandle); INLINE $3F3C,$0038,$A9E7; æDT LGetCell(dataPtr,dataLen,theCell,lHandle); æRI IV-272 æC Given a cell in theCell, LGetCell copies the cell’s data to the location specified by dataPtr; dataLen is the maximum number of bytes allowed. If the data is longer than dataLen, only dataLen bytes are copied into the location specified by dataPtr. If the data is shorter than dataLen, dataLen is set to the true length of the cell’s data. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LFind æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LFind(VAR offset: INTEGER;VAR len: INTEGER;theCell: Cell;lHandle: ListHandle); INLINE $3F3C,$0034,$A9E7; æDT LFind(offset,len,theCell,lHandle); æRI IV-274 æC Given a cell in theCell, LFind returns the offset and the length in bytes of the cell’s data. If an invalid cell is specified, offset and len are set to –1. A similar procedure, LGetCell, is more convenient to use from Pascal. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LRect æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LRect(VAR cellRect: Rect;theCell: Cell;lHandle: ListHandle); INLINE $3F3C,$004C,$A9E7; æDT LRect(cellRect,theCell,lHandle); æRI IV-274 æC LRect returns in cellRect the local (QuickDraw) coordinates of the cell specified by theCell. If an invalid cell is specified, (0,0)(0,0) is returned in cellRect. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LSetCell æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LSetCell(dataPtr: Ptr;dataLen: INTEGER;theCell: Cell;lHandle: ListHandle); INLINE $3F3C,$0058,$A9E7; æDT LSetCell(dataPtr,dataLen,theCell,lHandle); æRI IV-272 æC LSetCell places the data pointed to by dataPtr and of length dataLen into the specified cell. It replaces any data that was already in the cell. If dataLen is 0, this is equivalent to LClrCell. If theCell is not a valid cell, nothing is done. If drawing is off, you must turn drawing on and call LDraw (or LUpdate) to display the cell’s new value. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LSetSelect æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LSetSelect(setIt: BOOLEAN;theCell: Cell;lHandle: ListHandle); INLINE $3F3C,$005C,$A9E7; æDT LSetSelect(setIt,theCell,lHandle); æRI IV-273 æC If setIt is TRUE, LSetSelect selects the cell and redraws if it is visible and was previously unselected. If setIt is FALSE, it deselects the cell and redraws if necessary. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY LDraw æFp Lists.p æT PROCEDURE æTN $A9E7 æD PROCEDURE LDraw(theCell: Cell;lHandle: ListHandle); INLINE $3F3C,$0030,$A9E7; æDT LDraw(theCell,lHandle); æRI IV-275 æC Call LDraw after updating a cell’s data or selection status. (You can achieve the same result by invalidating the cell’s rectangle and calling LUpdate in response to the update event.) The List Manager makes its grafPort the current port, sets the clipping region to the cell’s rectangle, and calls the list definition procedure to draw the cell. It restores the clipping region and port before exiting. Assembly-language note: You can invoke each of the List Manager routines with a macro that has the same name as the routine preceded by an underscore. These macros expand to invoke to trap macro _Pack 0. The package determines which routine to execute from a routine selector, an integer that’s passed to it in a word on the stack. The routine selectors are as follows: lActivate .EQU 0 lAutoScroll .EQU 16 lAddColumn .EQU 4 lCellSize .EQU 20 lAddRow .EQU 8 lClick .EQU 24 lAddToCell .EQU 12 lClrCell .EQU 28 lDelColumn .EQU 32 lNew .EQU 68 lDelRow .EQU 36 lNextCell .EQU 72 lDispose .EQU 40 lRect .EQU 76 lDoDraw .EQU 44 lScroll .EQU 80 lDraw .EQU 48 lSearch .EQU 84 lFind .EQU 52 lSetCell .EQU 88 lGetCell .EQU 56 lSetSelect .EQU 92 lGetSelect .EQU 60 lSize .EQU 96 lLastClick .EQU 64 lUpdate .EQU 100 æKY Memory.p æKL ApplicZone BlockMove CompactMem DisposHandle DisposPtr EmptyHandle FreeMem GetApplLimit GetHandleSize GetPtrSize GetZone GZSaveHnd HandleZone HClrRBit HGetState HLock HNoPurge HPurge HSetRBit HSetState HUnlock InitApplZone InitZone MaxApplZone MaxBlock MaxMem MemError MFFreeMem MFMaxMem MFTempDisposHandle MFTempHLock MFTempHUnlock MFTempNewHandle MFTopMem MoreMasters MoveHHi NewEmptyHandle NewHandle NewHandleClear NewHandleSys NewHandleSysClear NewPtr NewPtrClear NewPtrSys NewPtrSysClear PtrZone PurgeMem PurgeSpace ReallocHandle RecoverHandle ResrvMem SetApplBase SetApplLimit SetGrowZone SetHandleSize SetPtrSize SetZone StackSpace StripAddress SystemZone TopMem maxSize Size THz Zone æKY maxSize æFp Memory.p æT CONST æD maxSize = $800000; {Max data block size is 8 megabytes} æC æKY Zone THz æFp Memory.p æT RECORD æD THz = ^Zone; Zone = RECORD bkLim: Ptr; purgePtr: Ptr; hFstFree: Ptr; zcbFree: LONGINT; gzProc: ProcPtr; moreMast: INTEGER; flags: INTEGER; cntRel: INTEGER; maxRel: INTEGER; cntNRel: INTEGER; maxNRel: INTEGER; cntEmpty: INTEGER; cntHandles: INTEGER; minCBFree: LONGINT; purgeProc: ProcPtr; sparePtr: Ptr; allocPtr: Ptr; heapData: INTEGER; END; æC »Structure of Heap Zones Each heap zone begins with a 52-byte zone header and ends with a 12-byte zone trailer (see Figure 11). The header contains all the information the Memory Manager needs about that heap zone; the trailer is just a minimum-size free block (described in the next section) placed at the end of the zone as a marker. All the remaining space between the header and trailer is available for allocation. In Pascal, a heap zone is defined as a zone record of type Zone. It’s always referred to with a zone pointer of type THz (“the heap zone”): TYPE THz = ^Zone; Zone = RECORD bkLim: Ptr; {zone trailer block} purgePtr: Ptr; {used internally} hFstFree: Ptr; {first free master pointer} zcbFree: LONGINT; {number of free bytes} gzProc: ProcPtr; {grow zone function} moreMast: INTEGER; {master pointers to allocate} flags: INTEGER; {used internally} cntRel: INTEGER; {not used} maxRel: INTEGER; {not used} cntNRel: INTEGER; {not used} maxNRel: INTEGER; {not used} cntEmpty: INTEGER; {not used} cntHandles: INTEGER; {not used} minCBFree: LONGINT; {not used} purgeProc: ProcPtr; {purge warning procedure} sparePtr: Ptr; {used internally} allocPtr: Ptr; {used internally} heapData: INTEGER {first usable byte in zone} END; Warning: The fields of the zone header are for the Memory Manager’s own internal use. You can examine the contents of the zone’s fields, but in general it doesn’t make sense for your program to try to change them. The few exceptions are noted below in the discussions of the specific fields. BkLim is a pointer to the zone’s trailer block. Since the trailer is the last block in the zone, bkLim is a pointer to the byte following the last byte of usable space in the zone. HFstFree is a pointer to the first free master pointer in the zone. Instead of just allocating space for one master pointer each time a relocatable block is created, the Memory Manager “preallocates” several master pointers at a time; as a group they form a nonrelocatable block. The moreMast field of the zone record tells the Memory Manager how many master pointers at a time to preallocate for this zone. Note: Master pointers are allocated 32 at a time for the system heap zone and 64 at a time for the application zone; this may be different on future versions of the Macintosh. All master pointers that are allocated but not currently in use are linked together into a list beginning in the hFstFree field. When you allocate a new relocatable block, the Memory Manager removes the first available master pointer from this list, sets it to point to the new block, and returns its address to you as a handle to the block. (If the list is empty, it allocates a fresh block of moreMast master pointers.) When you release a relocatable block, its master pointer isn’t released, but is linked onto the beginning of the list to be reused. Thus the amount of space devoted to master pointers can increase, but can never decrease until the zone is reinitialized. The zcbFree field always contains the number of free bytes remaining in the zone. As blocks are allocated and released, the Memory Manager adjusts zcbFree accordingly. This number represents an upper limit on the size of block you can allocate from this heap zone. Warning: It may not actually be possible to allocate a block as big as zcbFree bytes. Because nonrelocatable and locked blocks can’t be moved, it isn’t always possible to collect all the free space into a single block by compaction. The gzProc field is a pointer to the grow zone function. You can supply a pointer to your own grow zone function when you create a new heap zone and can change it at any time. Warning: Don’t store directly into the gzProc field; if you want to supply your own grow zone function, you must do so with a procedure call (InitZone or SetGrowZone). PurgeProc is a pointer to the zone’s purge warning procedure, or NIL if there is none. The Memory Manager will call this procedure before it purges a block from the zone. Warning: Whenever you call the Resource Manager with SetResPurge(TRUE), it installs its own purge warning procedure, overriding any purge warning procedure you’ve specified to the Memory Manager; for further details, see the Resource Manager chapter. The last field of a zone record, heapData, is a dummy field marking the bottom of the zone’s usable memory space. HeapData nominally contains an integer, but this integer has no significance in itself—it’s just the first two bytes in the block header of the first block in the zone. The purpose of the heapData field is to give you a way of locating the effective bottom of the zone. For example, if myZone is a zone pointer, then @(myZone^.heapData) is a pointer to the first usable byte in the zone, just as myZone^.bkLim is a pointer to the byte following the last usable byte in the zone. æKY Size æFp Memory.p æT RECORD æD Size = LONGINT; { size of a block in bytes } æC For specifying the sizes of blocks in the heap, the Memory Manager defines a special type called Size: TYPE Size = LONGINT; All Memory Manager routines that deal with block sizes expect parameters of type Size or return them as results. æKY GetApplLimit æFp Memory.p æT FUNCTION æD FUNCTION GetApplLimit: Ptr; INLINE $2EB8,$0130; æDT myVariable := GetApplLimit(paramList); æRI II-29 æC GetApplLimit returns the current application heap limit. It can be used in conjunction with SetApplLimit, described below, to determine and then change the application heap limit. Assembly-language note: The global variable ApplLimit contains the current application heap limit. æKY GetZone æFp Memory.p æT FUNCTION æD FUNCTION GetZone: THz; æDT myVariable := GetZone(paramList); æRI II-31 æC Trap macro _GetZone On exit A0: function result (pointer) D0: result code (word) GetZone returns a pointer to the current heap zone. Assembly-language note: The global variable TheZone contains a pointer to the current heap zone. Result codes noErr No error æKY SystemZone æFp Memory.p æT FUNCTION æD FUNCTION SystemZone: THz; INLINE $2EB8,$02A6; æDT myVariable := SystemZone(paramList); æRI II-32 æC [Not in ROM] SystemZone returns a pointer to the system heap zone. Assembly-language note: The global variable SysZone contains a pointer to the system heap zone. æKY ApplicZone æFp Memory.p æT FUNCTION æD FUNCTION ApplicZone: THz; INLINE $2EB8,$02AA; æDT myVariable := ApplicZone(paramList); æRI II-32, N83-1 æC [Not in ROM] ApplicZone returns a pointer to the original application heap zone. Assembly-language note: The global variable ApplZone contains a pointer to the original application heap zone. æKY NewHandle æFp Memory.p æT FUNCTION æD FUNCTION NewHandle(byteCount: Size): Handle; æDT myVariable := NewHandle(byteCount); æMM æRT 7, 117, 205 æRI I-76, 80, II-32, N7-2, N117-17, P-51, 177 æC Trap macro _NewHandle _NewHandle ,SYS (applies to system heap) _NewHandle ,CLEAR (clears allocated block) _NewHandle ,SYS,CLEAR (applies to system heap and clears allocated block) On entry D0: logicalSize (long word) On exit A0: function result (handle) D0: result code (word) NewHandle attempts to allocate a new relocatable block of logicalSize bytes from the current heap zone and then return a handle to it. The new block will be unlocked and unpurgeable. If logicalSize bytes can’t be allocated, NewHandle returns NIL. NewHandle will pursue all available avenues to create a free block of the requested size, including compacting the heap zone, increasing its size, purging blocks from it, and calling its grow zone function, if any. Result codes noErr No error memFullErr Not enough room in heap zone æKY NewHandleSys æFp Memory.p æT FUNCTION æD FUNCTION NewHandleSys(byteCount: Size): Handle; æDT myVariable := NewHandleSys(byteCount); æRT 219 æC Trap macro _NewHandle _NewHandle ,SYS (applies to system heap) _NewHandle ,CLEAR (clears allocated block) _NewHandle ,SYS,CLEAR (applies to system heap and clears allocated block) On entry D0: logicalSize (long word) On exit A0: function result (handle) D0: result code (word) NewHandle attempts to allocate a new relocatable block of logicalSize bytes from the current heap zone and then return a handle to it. The new block will be unlocked and unpurgeable. If logicalSize bytes can’t be allocated, NewHandle returns NIL. NewHandle will pursue all available avenues to create a free block of the requested size, including compacting the heap zone, increasing its size, purging blocks from it, and calling its grow zone function, if any. Result codes noErr No error memFullErr Not enough room in heap zone æKY NewHandleClear æFp Memory.p æT FUNCTION æD FUNCTION NewHandleClear(byteCount: Size): Handle; æDT myVariable := NewHandleClear(byteCount); æRT 219 æC Trap macro _NewHandle _NewHandle ,SYS (applies to system heap) _NewHandle ,CLEAR (clears allocated block) _NewHandle ,SYS,CLEAR (applies to system heap and clears allocated block) On entry D0: logicalSize (long word) On exit A0: function result (handle) D0: result code (word) NewHandle attempts to allocate a new relocatable block of logicalSize bytes from the current heap zone and then return a handle to it. The new block will be unlocked and unpurgeable. If logicalSize bytes can’t be allocated, NewHandle returns NIL. NewHandle will pursue all available avenues to create a free block of the requested size, including compacting the heap zone, increasing its size, purging blocks from it, and calling its grow zone function, if any. Result codes noErr No error memFullErr Not enough room in heap zone æKY NewHandleSysClear æFp Memory.p æT FUNCTION æD FUNCTION NewHandleSysClear(byteCount: Size): Handle; æDT myVariable := NewHandleSysClear(byteCount); æRT 219 æC Trap macro _NewHandle _NewHandle ,SYS (applies to system heap) _NewHandle ,CLEAR (clears allocated block) _NewHandle ,SYS,CLEAR (applies to system heap and clears allocated block) On entry D0: logicalSize (long word) On exit A0: function result (handle) D0: result code (word) NewHandle attempts to allocate a new relocatable block of logicalSize bytes from the current heap zone and then return a handle to it. The new block will be unlocked and unpurgeable. If logicalSize bytes can’t be allocated, NewHandle returns NIL. NewHandle will pursue all available avenues to create a free block of the requested size, including compacting the heap zone, increasing its size, purging blocks from it, and calling its grow zone function, if any. Result codes noErr No error memFullErr Not enough room in heap zone æKY HandleZone æFp Memory.p æT FUNCTION æD FUNCTION HandleZone(h: Handle): THz; æDT myVariable := HandleZone(h); æRI II-34 æC Trap macro _HandleZone On entry A0: h (handle) On exit A0: function result (pointer) D0: result code (word) HandleZone returns a pointer to the heap zone containing the relocatable block whose handle is h. In case of an error, the result returned by HandleZone is undefined and should be ignored. Warning: If handle h is empty (points to a NIL master pointer), HandleZone returns a pointer to the current heap zone. Result codes noErr No error memWZErr Attempt to operate on a free block æKY RecoverHandle æFp Memory.p æT FUNCTION æD FUNCTION RecoverHandle(p: Ptr): Handle; æDT myVariable := RecoverHandle(p); æMM æRT 23 æRI II-35, N8-1, N23-1 æC Trap macro _RecoverHandle _RecoverHandle ,SYS (applies to system heap) On entry A0: p (pointer) On exit A0: function result (handle) D0: unchanged RecoverHandle returns a handle to the relocatable block pointed to by p. Assembly-language note: The trap _RecoverHandle doesn’t return a result code in register D0; the previous contents of D0 are preserved unchanged. Result codes noErr No error [Pascal only] æKY NewPtr æFp Memory.p æT FUNCTION æD FUNCTION NewPtr(byteCount: Size): Ptr; æDT myVariable := NewPtr(byteCount); æMM æRI I-75, 79, II-36, P-51, 177 æC Trap macro _NewPtr _NewPtr ,SYS (applies to system heap) _NewPtr ,CLEAR (clears allocated block) _NewPtr ,SYS,CLEAR (applies to system heap and clears allocated block) On entry D0: logicalSize (long word) On exit A0: function result (pointer) D0: result code (word) NewPtr attempts to allocate a new nonrelocatable block of logicalSize bytes from the current heap zone and then return a pointer to it. If logicalSize bytes can’t be allocated, NewPtr returns NIL. NewPtr will pursue all available avenues to create a free block of the requested size at the lowest possible location in the heap zone, including compacting the heap zone, increasing its size, purging blocks from it, and calling its grow zone function, if any. Result codes noErr No error memFullErr Not enough room in heap zone æKY NewPtrSys æFp Memory.p æT FUNCTION æD FUNCTION NewPtrSys(byteCount: Size): Ptr; æDT myVariable := NewPtrSys(byteCount); æRT 219 æC Trap macro _NewPtr _NewPtr ,SYS (applies to system heap) _NewPtr ,CLEAR (clears allocated block) _NewPtr ,SYS,CLEAR (applies to system heap and clears allocated block) On entry D0: logicalSize (long word) On exit A0: function result (pointer) D0: result code (word) NewPtr attempts to allocate a new nonrelocatable block of logicalSize bytes from the current heap zone and then return a pointer to it. If logicalSize bytes can’t be allocated, NewPtr returns NIL. NewPtr will pursue all available avenues to create a free block of the requested size at the lowest possible location in the heap zone, including compacting the heap zone, increasing its size, purging blocks from it, and calling its grow zone function, if any. Result codes noErr No error memFullErr Not enough room in heap zone æKY NewPtrClear æFp Memory.p æT FUNCTION æD FUNCTION NewPtrClear(byteCount: Size): Ptr; æDT myVariable := NewPtrClear(byteCount); æRT 219 æC Trap macro _NewPtr _NewPtr ,SYS (applies to system heap) _NewPtr ,CLEAR (clears allocated block) _NewPtr ,SYS,CLEAR (applies to system heap and clears allocated block) On entry D0: logicalSize (long word) On exit A0: function result (pointer) D0: result code (word) NewPtr attempts to allocate a new nonrelocatable block of logicalSize bytes from the current heap zone and then return a pointer to it. If logicalSize bytes can’t be allocated, NewPtr returns NIL. NewPtr will pursue all available avenues to create a free block of the requested size at the lowest possible location in the heap zone, including compacting the heap zone, increasing its size, purging blocks from it, and calling its grow zone function, if any. Result codes noErr No error memFullErr Not enough room in heap zone æKY NewPtrSysClear æFp Memory.p æT FUNCTION æD FUNCTION NewPtrSysClear(byteCount: Size): Ptr; æDT myVariable := NewPtrSysClear(byteCount); æRT 219 æC Trap macro _NewPtr _NewPtr ,SYS (applies to system heap) _NewPtr ,CLEAR (clears allocated block) _NewPtr ,SYS,CLEAR (applies to system heap and clears allocated block) On entry D0: logicalSize (long word) On exit A0: function result (pointer) D0: result code (word) NewPtr attempts to allocate a new nonrelocatable block of logicalSize bytes from the current heap zone and then return a pointer to it. If logicalSize bytes can’t be allocated, NewPtr returns NIL. NewPtr will pursue all available avenues to create a free block of the requested size at the lowest possible location in the heap zone, including compacting the heap zone, increasing its size, purging blocks from it, and calling its grow zone function, if any. Result codes noErr No error memFullErr Not enough room in heap zone æKY PtrZone æFp Memory.p æT FUNCTION æD FUNCTION PtrZone(p: Ptr): THz; æDT myVariable := PtrZone(p); æRI II-38 æC Trap macro _PtrZone On entry A0: p (pointer) On exit A0: function result (pointer) D0: result code (word) PtrZone returns a pointer to the heap zone containing the nonrelocatable block pointed to by p. In case of an error, the result returned by PtrZone is undefined and should be ignored. Result codes noErr No error memWZErr Attempt to operate on a free block æKY GZSaveHnd æFp Memory.p æT FUNCTION æD FUNCTION GZSaveHnd: Handle; INLINE $2EB8,$0328; æDT myVariable := GZSaveHnd(paramList); æRI II-43 æC GZSaveHnd returns a handle to a relocatable block that must not be moved by the grow zone function, or NIL if there is no such block. Your grow zone function must be sure to call GZSaveHnd; if a handle is returned, it must ensure that this block is not moved. Assembly-language note: You can find the same handle in the global variable GZRootHnd. æKY TopMem æFp Memory.p æT FUNCTION æD FUNCTION TopMem: Ptr; INLINE $2EB8,$0108; æDT myVariable := TopMem(paramList); æRI II-44 æC [Not in ROM] On a Macintosh 128K or 512K, TopMem returns a pointer to the end of RAM; on the Macintosh XL, it returns a pointer to the end of the memory available for use by the application. Assembly-language note: This value is stored in the global variable MemTop. æKY MaxBlock æFp Memory.p æT FUNCTION æD FUNCTION MaxBlock: LONGINT; æDT myVariable := MaxBlock(paramList); æRI IV-77 æC Trap macro _MaxBlock _MaxBlock ,SYS (applies to system heap) On exit D0: function result (word) MaxBlock returns the maximum contiguous space in bytes that could be obtained by compacting the current zone (without actually doing the compaction). æKY StackSpace æFp Memory.p æT FUNCTION æD FUNCTION StackSpace: LONGINT; æDT myVariable := StackSpace(paramList); æRI IV-78 æC Trap macro _StackSpace On exit D0: function result (word) StackSpace returns the current amount of stack space between the current stack pointer and the application heap (at the instant of return from the trap). æKY NewEmptyHandle æFp Memory.p æT FUNCTION æD FUNCTION NewEmptyHandle: Handle; æDT myVariable := NewEmptyHandle(paramList); æMM æRI IV-78 æC Trap macro _NewEmptyHandle _NewEmptyHandle ,SYS (applies to system heap) On exit A0: function result (handle) D0: result code (word) NewEmptyHandle is similar in function to NewHandle except that it does not allocate any space; the handle returned is empty (in other words, it points to a NIL master pointer). NewEmptyHandle is used extensively by the Resource Manager; you may not need to use it. æKY HLock æFp Memory.p æT PROCEDURE æD PROCEDURE HLock(h: Handle); æDT HLock(h); æRT 2 æRI II-41, N2-3 æC The master pointer associated with each handle contains flags for use by the Memory Manager. Routines are provided for setting and clearing each of these flags, as well as for saving and restoring the entire byte. Warning: Failure to use these routines virtually guarantees incompatibility with future versions of the Macintosh. You should not set and clear these flags directly. The HLock and HUnlock procedures lock and unlock a given relocatable block by setting and clearing the lock flag. The HPurge and HNoPurge mark a given relocatable block as purgeable or unpurgeable by setting and clearing the purge flag. A third flag, the resource flag, is used internally by the Resource Manager. The HSetRBit and HClrRBit procedures set and clear this flag. The HSetState and HGetState routines let you save and restore the state of the flags byte. PROCEDURE HLock (h: Handle); Trap macro _HLock On entry A0: h (handle) On exit D0: result code (word) HLock locks a relocatable block, preventing it from being moved within its heap zone. If the block is already locked, HLock does nothing. Warning: To prevent heap fragmentation, you should always call MoveHHi before locking a relocatable block. Result codes noErr No error nilHandleErr NIL master pointer memWZErr Attempt to operate on a free block æKY HUnlock æFp Memory.p æT PROCEDURE æD PROCEDURE HUnlock(h: Handle); æDT HUnlock(h); æRT 2 æRI II-41, N2-3 æC The master pointer associated with each handle contains flags for use by the Memory Manager. Routines are provided for setting and clearing each of these flags, as well as for saving and restoring the entire byte. Warning: Failure to use these routines virtually guarantees incompatibility with future versions of the Macintosh. You should not set and clear these flags directly. The HLock and HUnlock procedures lock and unlock a given relocatable block by setting and clearing the lock flag. The HPurge and HNoPurge mark a given relocatable block as purgeable or unpurgeable by setting and clearing the purge flag. A third flag, the resource flag, is used internally by the Resource Manager. The HSetRBit and HClrRBit procedures set and clear this flag. The HSetState and HGetState routines let you save and restore the state of the flags byte. PROCEDURE HUnlock (h: Handle); Trap macro _HUnlock On entry A0: h (handle) On exit D0: result code (word) HUnlock unlocks a relocatable block, allowing it to be moved within its heap zone. If the block is already unlocked, HUnlock does nothing. Result codes noErr No error nilHandleErr NIL master pointer memWZErr Attempt to operate on a free block æKY HPurge æFp Memory.p æT PROCEDURE æD PROCEDURE HPurge(h: Handle); æDT HPurge(h); æRT 2 æRI II-41 æC Trap macro _HPurge On entry A0: h (handle) On exit D0: result code (word) HPurge marks a relocatable block as purgeable. If the block is already purgeable, HPurge does nothing. Note: If you call HPurge on a locked block, it won’t unlock the block, but it will mark the block as purgeable. If you later call HUnlock, the block will be subject to purging. Result codes noErr No error nilHandleErr NIL master pointer memWZErr Attempt to operate on a free block æKY HNoPurge æFp Memory.p æT PROCEDURE æD PROCEDURE HNoPurge(h: Handle); æDT HNoPurge(h); æRT 2 æRI II-42, N2-3 æC Trap macro _HNoPurge On entry A0: h (handle) On exit D0: result code (word) HNoPurge marks a relocatable block as unpurgeable. If the block is already unpurgeable, HNoPurge does nothing. Result codes noErr No error nilHandleErr NIL master pointer memWZErr Attempt to operate on a free block æKY StripAddress æFp Memory.p æT FUNCTION æD FUNCTION StripAddress(theAddress: Ptr): Ptr; æDT myVariable := StripAddress(theAddress); æRT 212,213 æRI V-593 æC Trap macro _StripAddress On entry D0: theAddress (pointer) On exit D0: function result (pointer) The original description of StripAddress was incorrect. Technical Note #213 correctly documents this function. •••Refer to Technical Note #213:••• æKY MFMaxMem æFp Memory.p æT FUNCTION æTN A88F æD FUNCTION MFMaxMem(VAR grow: Size): Size; INLINE $3F3C,$0015,$A88F; æDT myVariable := MFMaxMem(grow); æC æKY MFFreeMem æFp Memory.p æT FUNCTION æTN A88F æD FUNCTION MFFreeMem: LONGINT; INLINE $3F3C,$0018,$A88F; æDT myVariable := MFFreeMem(paramList); æC æKY MFTempNewHandle æFp Memory.p æT FUNCTION æTN A88F æD FUNCTION MFTempNewHandle(logicalSize: Size;VAR resultCode: OSErr): Handle; INLINE $3F3C,$001D,$A88F; æDT myVariable := MFTempNewHandle(logicalSize,resultCode); æRT 205 æC æKY MFTempHLock æFp Memory.p æT PROCEDURE æTN A88F æD PROCEDURE MFTempHLock(h: Handle;VAR resultCode: OSErr); INLINE $3F3C,$001E,$A88F; æDT MFTempHLock(h,resultCode); æC æKY MFTempHUnlock æFp Memory.p æT PROCEDURE æTN A88F æD PROCEDURE MFTempHUnlock(h: Handle;VAR resultCode: OSErr); INLINE $3F3C,$001F,$A88F; æDT MFTempHUnlock(h,resultCode); æC æKY MFTempDisposHandle æFp Memory.p æT PROCEDURE æTN A88F æD PROCEDURE MFTempDisposHandle(h: Handle;VAR resultCode: OSErr); INLINE $3F3C,$0020,$A88F; æDT MFTempDisposHandle(h,resultCode); æC æKY MFTopMem æFp Memory.p æT FUNCTION æTN A88F æD FUNCTION MFTopMem: Ptr; INLINE $3F3C,$0016,$A88F; æDT myVariable := MFTopMem(paramList); æC æKY InitApplZone æFp Memory.p æT PROCEDURE æTN A02C æD PROCEDURE InitApplZone; INLINE $A02C; æDT InitApplZone(paramList); æMM æRI II-28, N64-2 æC Trap macro _InitApplZone On exit D0: result code (word) InitApplZone initializes the application heap zone and makes it the current zone. The contents of any previous application zone are lost; all previously existing blocks in that zone are discarded. The zone’s grow zone function is set to NIL. InitApplZone is called by the Segment Loader when starting up an application; you shouldn’t normally need to call it. Warning: Reinitializing the application zone from within a running program is tricky, since the program’s code itself normally resides in the application zone. To do it safely, the code containing the InitApplZone call cannot be in the application zone. Result codes noErr No error æKY InitZone æFp Memory.p æT PROCEDURE æD PROCEDURE InitZone(pgrowZone: ProcPtr;cmoreMasters: INTEGER;limitPtr: Ptr; startPtr: Ptr); æDT InitZone(pgrowZone,cmoreMasters,limitPtr,startPtr); æMM æRI II-29 æC Trap macro _InitZone On entry A0: pointer to parameter block Parameter block 0 startPtr pointer 4 limitPtr pointer 8 cMoreMasters word 10 pGrowZone pointer On exit D0: result code (word) InitZone creates a new heap zone, initializes its header and trailer, and makes it the current zone. The startPtr parameter is a pointer to the first byte of the new zone; limitPtr points to the first byte beyond the end of the zone. The new zone will occupy memory addresses from ORD(startPtr) through ORD(limitPtr)–1. CMoreMasters tells how many master pointers should be allocated at a time for the new zone. This number of master pointers are created initially; should more be needed later, they’ll be added in increments of this same number. The pGrowZone parameter is a pointer to the grow zone function for the new zone, if any. If you’re not defining a grow zone function for this zone, pass NIL. The new zone includes a 52-byte header and a 12-byte trailer, so its actual usable space runs from ORD(startPtr)+52 through ORD(limitPtr)–13. In addition, there’s an eight-byte header for the master pointer block, as well as four bytes for each master pointer, within this usable area. Thus the total available space in the zone, in bytes, is initially ORD(limitPtr) – ORD(startPtr) – 64 – (8 + (4*cMoreMasters)) This number must not be less than 0. Note that the amount of available space in the zone will decrease as more master pointers are allocated. Result codes noErr No error æKY SetZone æFp Memory.p æT PROCEDURE æD PROCEDURE SetZone(hz: THz); æDT SetZone(hz); æRI II-31, N8-1 æC Trap macro _SetZone On entry A0: hz (pointer) On exit D0: result code (word) SetZone sets the current heap zone to the zone pointed to by hz. Assembly-language note: You can set the current heap zone by storing a pointer to it in the global variable TheZone. Result codes noErr No error æKY CompactMem æFp Memory.p æT FUNCTION æD FUNCTION CompactMem(cbNeeded: Size): Size; æDT myVariable := CompactMem(cbNeeded); æMM æRT 51 æRI II-39, N51-1 æC Trap macro _CompactMem _CompactMem ,SYS (applies to system heap) On entry D0: cbNeeded (long word) On exit D0: function result (long word) CompactMem compacts the current heap zone by moving relocatable blocks down and collecting free space together until a contiguous block of at least cbNeeded free bytes is found or the entire zone is compacted; it doesn’t purge any purgeable blocks. CompactMem returns the size in bytes of the largest contiguous free block remaining. Note that it doesn’t actually allocate the block. Result codes noErr No error [Pascal only] æKY PurgeMem æFp Memory.p æT PROCEDURE æD PROCEDURE PurgeMem(cbNeeded: Size); æDT PurgeMem(cbNeeded); æMM æRT 51 æRI II-40, N51-1 æC Trap macro _PurgeMem _PurgeMem ,SYS (applies to system heap) On entry D0: cbNeeded (long word) On exit D0: result code (word) PurgeMem sequentially purges blocks from the current heap zone until a contiguous block of at least cbNeeded free bytes is created or the entire zone is purged; it doesn’t compact the heap zone. Only relocatable, unlocked, purgeable blocks can be purged. Note that PurgeMem doesn’t actually allocate the block. Result codes noErr No error memFullErr Not enough room in heap zone æKY FreeMem æFp Memory.p æT FUNCTION æD FUNCTION FreeMem: LONGINT; æDT myVariable := FreeMem(paramList); æMM æRI II-38 æC Trap macro _FreeMem _FreeMem ,SYS (applies to system heap) On exit D0: function result (long word) FreeMem returns the total amount of free space in the current heap zone, in bytes. Note that it usually isn’t possible to allocate a block of this size, because of fragmentation due to nonrelocatable or locked blocks. Result codes noErr No error [Pascal only] æKY ResrvMem æFp Memory.p æT PROCEDURE æD PROCEDURE ResrvMem(cbNeeded: Size); æDT ResrvMem(cbNeeded); æMM æRI II-39 æC Trap macro _ResrvMem _ResrvMem ,SYS (applies to system heap) On entry D0: cbNeeded (long word) On exit D0: result code (word) ResrvMem creates free space for a block of cbNeeded contiguous bytes at the lowest possible position in the current heap zone. It will try every available means to place the block as close as possible to the bottom of the zone, including moving other blocks upward, expanding the zone, or purging blocks from it. Note that ResrvMem doesn’t actually allocate the block. Note: When you allocate a relocatable block that you know will be locked for long periods of time, call ResrvMem first. This reserves space for the block near the bottom of the heap zone, where it will interfere with compaction as little as possible. It isn’t necessary to call ResrvMem for a nonrelocatable block; NewPtr calls it automatically. It’s also called automatically when locked resources are read into memory. Result codes noErr No error memFullErr Not enough room in heap zone æKY MaxMem æFp Memory.p æT FUNCTION æD FUNCTION MaxMem(VAR grow: Size): Size; æDT myVariable := MaxMem(grow); æRI II-38 æC Trap macro _MaxMem _MaxMem ,SYS (applies to system heap) On exit D0: function result (long word) A0: grow (long word) MaxMem compacts the current heap zone and purges all purgeable blocks from the zone. It returns as its result the size in bytes of the largest contiguous free block in the zone after the compaction. If the current zone is the original application heap zone, the grow parameter is set to the maximum number of bytes by which the zone can grow. For any other heap zone, grow is set to 0. MaxMem doesn’t actually expand the zone or call its grow zone function. Result codes noErr No error [Pascal only] æKY SetGrowZone æFp Memory.p æT PROCEDURE æD PROCEDURE SetGrowZone(growZone: ProcPtr); æDT SetGrowZone(growZone); æRI II-42 æC Trap macro _SetGrowZone On entry A0: growZone (pointer) On exit D0: result code (word) SetGrowZone sets the current heap zone’s grow zone function as designated by the growZone parameter. A NIL parameter value removes any grow zone function the zone may previously have had. Note: If your program presses the limits of the available heap space, it’s a good idea to have a grow zone function of some sort. At the very least, the grow zone function should take some graceful action—such as displaying an alert box with the message “Out of memory”—instead of just failing unpredictably. If it has failed to create a block of the needed size after compacting the zone, increasing its size (in the case of the original application zone), and purging blocks from it, the Memory Manager calls the grow zone function as a last resort. The grow zone function should be of the form FUNCTION MyGrowZone (cbNeeded: Size) : LONGINT; The cbNeeded parameter gives the physical size of the needed block in bytes, including the block header. The grow zone function should attempt to create a free block of at least this size. It should return a nonzero number if it’s able to allocate some memory, or 0 if it’s not able to allocate any. If the grow zone function returns 0, the Memory Manager will give up trying to allocate the needed block and will signal failure with the result code memFullErr. Otherwise it will compact the heap zone and try again to allocate the block. If still unsuccessful, it will continue to call the grow zone function repeatedly, compacting the zone again after each call, until it either succeeds in allocating the needed block or receives a zero result and gives up. The usual way for the grow zone function to free more space is to call EmptyHandle to purge blocks that were previously marked unpurgeable. Another possibility is to unlock blocks that were previously locked Note: Although just unlocking blocks doesn’t actually free any additional space in the zone, the grow zone function should still return a nonzero result in this case. This signals the Memory Manager to compact the heap and try again to allocate the needed block. Warning: Depending on the circumstances in which the grow zone function is called, there may be a particular block within the heap zone that must not be moved. For this reason, it’s essential that your grow zone function call the function GZSaveHnd (see below). Result codes noErr No error æKY SetApplLimit æFp Memory.p æT PROCEDURE æD PROCEDURE SetApplLimit(zoneLimit: Ptr); æDT SetApplLimit(zoneLimit); æRI II-30 æC Trap macro _SetApplLimit On entry A0: zoneLimit (pointer) On exit D0: result code (word) SetApplLimit sets the application heap limit, beyond which the application heap can’t be expanded. The actual expansion isn’t under your program’s control, but is done automatically by the Memory Manager when necessary to satisfy allocation requests. Only the original application zone can be expanded. ZoneLimit is a pointer to a byte in memory beyond which the zone will not be allowed to grow. The zone can grow to include the byte preceding zoneLimit in memory, but no farther. If the zone already extends beyond the specified limit it won’t be cut back, but it will be prevented from growing any more. Warning: Notice that zoneLimit is not a byte count. To limit the application zone to a particular size (say 8K bytes), you have to write something like SetApplLimit(Ptr(ApplicZone)+8192) The Memory Manager function ApplicZone is explained below. Assembly-language note: You can just store the new application heap limit in the global variable ApplLimit. Result codes noErr No error memFullErr Not enough room in heap zone æKY MoveHHi æFp Memory.p æT PROCEDURE æD PROCEDURE MoveHHi(h: Handle); æDT MoveHHi(h); æMM æRT 103, 111 æRI II-44, IV-77, 83, N103, N111 æC [Not in 64K ROM] Trap macro _MoveHHi On entry A0: h (handle) On exit D0: result code (word) MoveHHi moves the relocatable block whose handle is h toward the top of the current heap zone, until the block hits either a nonrelocatable block, a locked relocatable block, or the last block in the current heap zone. By calling MoveHHi before you lock a relocatable block, you can avoid fragmentation of the heap, as well as make room for future pointers as low in the heap as possible. Result codes noErr No error nilHandleErr NIL master pointer memLockedErr Block is locked æKY DisposPtr æFp Memory.p æT PROCEDURE æD PROCEDURE DisposPtr(p: Ptr); æDT DisposPtr(p); æMM æRI I-75, 79, II-36, P-51, 169 æC Trap macro _DisposPtr On entry A0: p (pointer) On exit D0: result code (word) DisposPtr releases the memory occupied by the nonrelocatable block pointed to by p. Warning: After a call to DisposPtr, all pointers to the released block become invalid and should not be used again. Any subsequent calls to DisposPtr using an invalid pointer will damage the master pointer list. Result codes noErr No error memWZErr Attempt to operate on a free block æKY GetPtrSize æFp Memory.p æT FUNCTION æD FUNCTION GetPtrSize(p: Ptr): Size; æDT myVariable := GetPtrSize(p); æRI II-37 æC Trap macro _GetPtrSize On entry A0: p (pointer) On exit D0: if >= 0, function result (long word) if < 0, result code (word) GetPtrSize returns the logical size, in bytes, of the nonrelocatable block pointed to by p. In case of an error, GetPtrSize returns 0. Assembly-language note: Recall that the trap dispatcher sets the condition codes before returning from a trap by testing the low-order word of register D0 with a TST.W instruction. Since the block size returned in D0 by _GetPtrSize is a full 32-bit long word, the word-length test sets the condition codes incorrectly in this case. To branch on the contents of D0, use your own TST.L instruction on return from the trap to test the full 32 bits of the register. Result codes noErr No error [Pascal only] memWZErr Attempt to operate on a free block æKY SetPtrSize æFp Memory.p æT PROCEDURE æD PROCEDURE SetPtrSize(p: Ptr;newSize: Size); æDT SetPtrSize(p,newSize); æMM æRI II-37 æC Trap macro _SetPtrSize On entry A0: p (pointer) D0: newSize (long word) On exit D0: result code (word) SetPtrSize changes the logical size of the nonrelocatable block pointed to by p to newSize bytes. Result codes noErr No error memFullErr Not enough room in heap zone memWZErr Attempt to operate on a free block æKY DisposHandle æFp Memory.p æT PROCEDURE æD PROCEDURE DisposHandle(h: Handle); æDT DisposHandle(h); æMM æRI I-76, 80, II-33, N8-1, P-51, 168 æC Trap macro _DisposHandle On entry A0: h (handle) On exit D0: result code (word) DisposHandle releases the memory occupied by the relocatable block whose handle is h. Warning: After a call to DisposHandle, all handles to the released block become invalid and should not be used again. Any subsequent calls to DisposHandle using an invalid handle will damage the master pointer list. Result codes noErr No error memWZErr Attempt to operate on a free block æKY GetHandleSize æFp Memory.p æT FUNCTION æD FUNCTION GetHandleSize(h: Handle): Size; æDT myVariable := GetHandleSize(h); æRI II-33, N54-1, N63-1 æC Trap macro _GetHandleSize On entry A0: h (handle) On exit D0: if >= 0, function result (long word) if < 0, result code (word) GetHandleSize returns the logical size, in bytes, of the relocatable block whose handle is h. In case of an error, GetHandleSize returns 0. Assembly-language note: Recall that the trap dispatcher sets the condition codes before returning from a trap by testing the low-order word of register D0 with a TST.W instruction. Since the block size returned in D0 by _GetHandleSize is a full 32-bit long word, the word-length test sets the condition codes incorrectly in this case. To branch on the contents of D0, use your own TST.L instruction on return from the trap to test the full 32 bits of the register. Result codes noErr No error [Pascal only] nilHandleErr NIL master pointer memWZErr Attempt to operate on a free block æKY SetHandleSize æFp Memory.p æT PROCEDURE æD PROCEDURE SetHandleSize(h: Handle;newSize: Size); æDT SetHandleSize(h,newSize); æMM æRI II-34 æC Trap macro _SetHandleSize On entry A0: h (handle) D0: newSize (long word) On exit D0: result code (word) SetHandleSize changes the logical size of the relocatable block whose handle is h to newSize bytes. Note: Be prepared for an attempt to increase the size of a locked block to fail, since there may be a block above it that’s either nonrelocatable or locked. Result codes noErr No error memFullErr Not enough room in heap zone nilHandleErr NIL master pointer memWZErr Attempt to operate on a free block æKY EmptyHandle æFp Memory.p æT PROCEDURE æD PROCEDURE EmptyHandle(h: Handle); æDT EmptyHandle(h); æMM æRI II-40 æC Trap macro _EmptyHandle On entry A0: h (handle) On exit A0: h (handle) D0: result code (word) EmptyHandle purges the relocatable block whose handle is h from its heap zone and sets its master pointer to NIL (making it an empty handle). If h is already empty, EmptyHandle does nothing. Note: Since the space occupied by the block’s master pointer itself remains allocated, all handles pointing to it remain valid but empty. When you later reallocate space for the block with ReallocHandle, the master pointer will be updated, causing all existing handles to access the new block correctly. The block whose handle is h must be unlocked, but need not be purgeable. Result codes noErr No error memWZErr Attempt to operate on a free block memPurErr Attempt to purge a locked block æKY ReallocHandle æFp Memory.p æT PROCEDURE æD PROCEDURE ReallocHandle(h: Handle;byteCount: Size); æDT ReallocHandle(h,byteCount); æMM æRI ReallocHandle procedure II-35 æC PROCEDURE ReallocHandle (h: Handle; logicalSize: Size); _________________________________________________ Trap macro _ReallocHandle On entry A0: h (handle) D0: logicalSize (integer) On exit A0: original h or 0 D0: result code (integer) _________________________________________________ ReallocHandle allocates a new relocatable block with a logical size of logicalSize bytes. It then updates handle h by setting its master pointer to point to the new block. The main use of this procedure is to reallocate space for a block that has been purged. Normally h is an empty handle, but it need not be: if it points to an existing block, that block is released before the new block is created. In case of an error, no new block is allocated and handle h is left unchanged. _________________________________________________ Assembly-language note: On return from ReallocHandle, register A0 contains the original handle h, or 0 if no room could be found for the requested block. _________________________________________________ Result codes noErr Noerror memFullErr Not enough room in zone memWZErr Attempt to operate on a free block MemPurErr Block is locked æKY HSetRBit æFp Memory.p æT PROCEDURE æD PROCEDURE HSetRBit(h: Handle); æDT HSetRBit(h); æRT 2 æRI IV-79, N2-3 æC Trap macro _HSetRBit On entry A0: h (handle) On exit D0: result code (word) HSetRBit sets the resource flag of a relocatable block’s master pointer. æKY HClrRBit æFp Memory.p æT PROCEDURE æD PROCEDURE HClrRBit(h: Handle); æDT HClrRBit(h); æRT 2 æRI IV-79, N2-3 æC Trap macro _HClrRBit On entry A0: h (handle) On exit D0: result code (word) HClrRBit clears the resource flag of a relocatable block’s master pointer. æKY MoreMasters æFp Memory.p æT PROCEDURE æTN A036 æD PROCEDURE MoreMasters; INLINE $A036; æDT MoreMasters(paramList); æMM æRT 53 æRI II-31, N53 æC Trap macro _MoreMasters MoreMasters allocates another block of master pointers in the current heap zone. This procedure is usually called very early in an application. Result codes noErr No error memFullErr Not enough room in heap zone æKY BlockMove æFp Memory.p æT PROCEDURE æD PROCEDURE BlockMove(srcPtr: Ptr;destPtr: Ptr;byteCount: Size); æDT BlockMove(srcPtr,destPtr,byteCount); æRI II-44 æC Trap macro _BlockMove On entry A0: sourcePtr (pointer) A1: destPtr (pointer) D0: byteCount (long word) On exit D0: result code (word) BlockMove moves a block of byteCount consecutive bytes from the address designated by sourcePtr to that designated by destPtr. No pointers are updated. BlockMove works correctly even if the source and destination blocks overlap. Result codes noErr No error æKY MemError æFp Memory.p æT FUNCTION æD FUNCTION MemError: OSErr; INLINE $3EB8,$0220; æDT myVariable := MemError(paramList); æRT 7 æRI II-44, N7-2 æC All Memory Manager routines (including the RecoverHandle function) return a result code that you can examine by calling the MemError function. Assembly-language note: The trap _RecoverHandle doesn’t return a result code in register D0. The result code of the most recent call, however, is always stored in the global variable MemErr. FUNCTION MemError : OSErr; [Not in ROM] MemError returns the result code produced by the last Memory Manager routine called directly by your program. (OSErr is an Operating System Utility data type declared as INTEGER.) Assemby-language note: To get a routine’s result code from assembly language, look in register D0 on return from the routine (except for certain routines as noted). æKY PurgeSpace æFp Memory.p æT PROCEDURE æD PROCEDURE PurgeSpace(VAR total: LONGINT;VAR contig: LONGINT); æDT PurgeSpace(total,contig); æRI IV-78 æC Trap macro _PurgeSpace _PurgeSpace ,SYS (applies to system heap) On exit A0: contig (long word) D0: total (long word) PurgeSpace returns in total the total amount of space in bytes that could be obtained by a general purge (without actually doing the purge); this amount includes space that is already free. The maximum contiguous space in bytes (including already free space) that could be obtained by a purge is returned in contig. æKY HGetState æFp Memory.p æT FUNCTION æD FUNCTION HGetState(h: Handle): SignedByte; æDT myVariable := HGetState(h); æRT 2 æRI IV-79, N2-3 æC Trap macro _HGetState On entry A0: h (handle) On exit D0: flags (byte) HGetState returns the byte that contains the flags of the master pointer for the given handle; it’s used in conjunction with HSetState to save and restore the state of the flags contained in this byte. You can save this byte, change the state of any of the flags (using the routines described above), and then restore their original state by passing the byte back to the HSetState procedure (described below). æKY HSetState æFp Memory.p æT PROCEDURE æD PROCEDURE HSetState(h: Handle;flags: SignedByte); æDT HSetState(h,flags); æRT 2 æRI IV-80, N2-3 æC Trap macro _HSetState On entry A0: h (handle) D0: flags (byte) On exit D0: result code (word) HSetState is used in conjunction with HGetState; it sets the byte that contains the flags of the master pointer for the given handle to the byte specified by flags. æKY SetApplBase æFp Memory.p æT PROCEDURE æD PROCEDURE SetApplBase(startPtr: Ptr); æDT SetApplBase(startPtr); æMM æRI II-28 æC Trap macro _SetAppBase On entry A0: startPtr (pointer) On exit D0: result code (word) SetApplBase changes the starting address of the application heap zone to the address designated by startPtr, and then calls InitApplZone. SetApplBase is normally called only by the system itself; you should never need to call this procedure. Since the application heap zone begins immediately following the end of the system zone, changing its starting address has the effect of changing the size of the system zone. The system zone can be made larger, but never smaller; if startPtr points to an address lower than the current end of the system zone, it’s ignored and the application zone’s starting address is left unchanged. Warning: Like InitApplZone, SetApplBase is a tricky operation, because the program’s code itself normally resides in the application heap zone. To do it safely, the code containing the SetApplBase call cannot be in the application zone. Result codes noErr No error æKY MaxApplZone æFp Memory.p æT PROCEDURE æTN A063 æD PROCEDURE MaxApplZone; INLINE $A063; æDT MaxApplZone(paramList); æRT 103 æRI II-30, IV-77, 83, N39-1, N103 æC Trap macro _MaxApplZone On exit D0: result code (word) MaxApplZone expands the application heap zone to the application heap limit without purging any blocks currently in the zone. If the zone already extends to the limit, it won’t be changed. Assembly-language note: To expand the application heap zone to the application heap limit from assembly language, call this Pascal procedure from your program. Result codes noErr No error æKY Menus.p æKL AddResMenu AppendMenu CalcMenuSize CheckItem ClearMenuBar CountMItems DeleteMenu DelMCEntries DelMenuItem DisableItem DispMCInfo DisposeMenu DrawMenuBar EnableItem FlashMenuBar GetItem GetItemCmd GetItemIcon GetItemMark GetItemStyle GetMCEntry GetMCInfo GetMenu GetMenuBar GetMHandle GetNewMBar HiliteMenu InitMenus InitProcMenu InsertMenu InsertResMenu InsMenuItem InvalidMenuBar MenuChoice MenuKey MenuSelect NewMenu PopUpMenuSelect SetItem SetItemCmd SetItemIcon SetItemMark SetItemStyle SetMCEntries SetMCInfo SetMenuBar SetMenuFlash hierMenu hMenuCmd mCalcItemMsg MCEntry MCEntryPtr mChooseMsg MCTable MCTableHandle MCTablePtr mctAllItems mctLastIDIndic mDrawItemMsg mDrawMsg MenuCRsrc MenuCRsrcHandle MenuCRsrcPtr MenuHandle MenuInfo MenuPtr mPopUpMsg mSizeMsg noMark textMenuProc æKY noMark æFp Menus.p æT CONST æD noMark = 0; {mark symbol for MarkItem} æC æKY mDrawMsg æFp Menus.p æT CONST æD { menu defProc messages } mDrawMsg = 0; æC _______________________________________________________________________________ »The Menu Definition Procedure The menu definition procedure is usually written in assembly language, but may be written in any high-level language. Assembly-language note: The procedure’s entry point must be at the beginning. You may choose any name you wish for the menu definition procedure. Here’s how you would declare one named MyMenu: PROCEDURE MyMenu (message: INTEGER; theMenu: MenuHandle; VAR menuRect: Rect; hitPt: Point; VAR whichItem: INTEGER); The message parameter identifies the operation to be performed. It has one of the following values: CONST mDrawMsg = 0; {draw the menu} mChooseMsg = 1; {tell which item was chosen and highlight it} mSizeMsg = 2; {calculate the menu's dimensions} The parameter theMenu indicates the menu that the operation will affect. MenuRect is the rectangle (in global coordinates) in which the menu is located; it’s used when the message is mDrawMsg or mChooseMsg. Note: MenuRect is declared as a VAR parameter not because its value is changed, but because of a Pascal feature that will cause an error when that parameter isn’t used. The message mDrawMsg tells the menu definition procedure to draw the menu inside menuRect. The current grafPort will be the Window Manager port. (For details on drawing, see the QuickDraw chapter.) The standard menu definition procedure figures out how to draw the menu items by looking in the menu record at the data that defines them; this data is described in detail under “Formats of Resources for Menus” below. For menus of your own definition, you may set up the data defining the menu items any way you like, or even omit it altogether (in which case all the information necessary to draw the menu would be in the menu definition procedure itself). You should also check the enableFlags field of the menu record to see whether the menu is disabled (or whether any of the menu items are disabled, if you’re using all the flags), and if so, draw it in gray. Note: MenuKey will always search the menuData field of a MenuInfo record for Command-key equivalents until it finds a zero where a standard menu title should be, even if the MenuInfo record is for one of your own 'MDEF' resources. To prevent MenuKey from finding a Command-key equivalent in your MenuInfo record, put a couple of bytes of zeros just after the menu’s title. Warning: Don’t change the font from the system font for menu text. (The Window Manager port uses the system font.) When the menu definition procedure receives the message mChooseMsg, the hitPt parameter is the mouse location (in global coordinates), and the whichItem parameter is the item number of the last item that was chosen from this menu (whichItem is initially set to 0). The procedure should determine whether the mouse location is in an enabled menu item, by checking whether hitPt is inside menuRect, whether the menu is enabled, and whether hitPt is in an enabled menu item: • If the mouse location is in an enabled menu item, unhighlight whichItem and highlight the new item (unless the new item is the same as the whichItem), and return the item number of the new item in whichItem. • If the mouse location isn’t in an enabled item, unhighlight whichItem and return 0. Note: When the Menu Manager needs to make a chosen menu item blink, it repeatedly calls the menu definition procedure with the message mChooseMsg, causing the item to be alternately highlighted and unhighlighted. Finally, the message mSizeMsg tells the menu definition procedure to calculate the horizontal and vertical dimensions of the menu and store them in the menuWidth and menuHeight fields of the menu record. The following section describes changes to the default menu definition procedure ('MDEF' resource 0); some of the information presented in this section is accessible only through assembly language. Note: These features will work with the 64K ROM if the new menu definition procedure is in the system resource file. »Variable Size Fonts Menus are displayed in the system font. Since the system font and font size can now be changed, the menu definition procedure calls the QuickDraw procedure GetFontInfo for the system font to determine the height of menu items »Scrolling Menus The default menu definition procedure allows longer menus by implementing automatic scrolling. If the entire menu cannot be drawn on screen, dragging the cursor below the last displayed item will cause the items in the menu to scroll up. Similarly, if items have been scrolled past the top of the menu, dragging the cursor into the highlighted portion of the menu bar will cause the menu to scroll back down. The maximum number of items that can be drawn on the standard Macintosh screen with this new menu definition function is 19 (instead of 20). Warning: You should not disable any menu items in a menu containing more than 31 items because the enableFlags field of the MenuInfoRec can only handle 31 items. æKY mChooseMsg æFp Menus.p æT CONST æD mChooseMsg = 1; æC æKY mSizeMsg æFp Menus.p æT CONST æD mSizeMsg = 2; æC æKY mDrawItemMsg æFp Menus.p æT CONST æD mDrawItemMsg = 4; æC æKY mCalcItemMsg æFp Menus.p æT CONST æD mCalcItemMsg = 5; æC æKY textMenuProc æFp Menus.p æT CONST æD textMenuProc = 0; æC æKY hMenuCmd æFp Menus.p æT CONST æD hMenuCmd = 27; {itemCmd == 0x001B ==> hierarchical menu} æC æKY hierMenu æFp Menus.p æT CONST æD hierMenu = -1; {a hierarchical menu - for InsertMenu call} æC æKY mPopUpMsg æFp Menus.p æT CONST æD mPopUpMsg = 3; {menu defProc messages - place yourself} æC æKY mctAllItems æFp Menus.p æT CONST æD mctAllItems = -98; {search for all Items for the given ID} æC æKY mctLastIDIndic æFp Menus.p æT CONST æD mctLastIDIndic = -99; {last color table entry has this in ID field} æC æKY MenuInfo MenuPtr MenuHandle æFp Menus.p æT RECORD æD MenuPtr = ^MenuInfo; MenuHandle = ^MenuPtr; MenuInfo = RECORD menuID: INTEGER; menuWidth: INTEGER; menuHeight: INTEGER; menuProc: Handle; enableFlags: LONGINT; menuData: Str255; END; æC _______________________________________________________________________________ »MENU MANAGER DATA STRUCTURES _______________________________________________________________________________ The Menu Manager keeps all the information it needs for its operations on a particular menu in a menu record. The menu record contains the following: • The menu ID, a number that identifies the menu. The menu ID can be the same number as the menu’s resource ID, though it doesn’t have to be. • The menu title. • The contents of the menu—the text and other parts of each item. • The horizontal and vertical dimensions of the menu, in pixels. The menu items appear inside the rectangle formed by these dimensions; the black border and shadow of the menu appear outside that rectangle. • A handle to the menu definition procedure. • Flags telling whether each menu item is enabled or disabled, and whether the menu itself is enabled or disabled. The data type for a menu record is called MenuInfo. A menu record is referred to by a handle: TYPE MenuPtr = ^MenuInfo; MenuHandle = ^MenuPtr; You can store into and access all the necessary fields of a menu record with Menu Manager routines, so normally you don’t have to know the exact field names. However, if you want more information about the exact structure of a menu record—if you’re defining your own menu types, for instance—it’s given below. _______________________________________________________________________________ »The MenuInfo Data Type The type MenuInfo is defined as follows: TYPE MenuInfo = RECORD menuID: INTEGER; {menu ID} menuWidth: INTEGER; {menu width in pixels} menuHeight: INTEGER; {menu height in pixels} menuProc: Handle; {menu definition procedure} enableFlags: LONGINT; {tells if menu or items are enabled} menuData: Str255 {menu title (and